Moved dependencies into separate repo
All checks were successful
/ Build the server (push) Successful in 3m4s
All checks were successful
/ Build the server (push) Successful in 3m4s
This commit is contained in:
parent
023ef2ec49
commit
7334bd8e71
@ -10,5 +10,8 @@
|
||||
<file path="$PROJECT_DIR$/lib/restbed-4.8" />
|
||||
<file path="$PROJECT_DIR$/phc-winner-argon2-20190702" />
|
||||
</libraryRoots>
|
||||
<excludeRoots>
|
||||
<file path="$PROJECT_DIR$/cmake-build-debug" />
|
||||
</excludeRoots>
|
||||
</component>
|
||||
</project>
|
@ -1,55 +0,0 @@
|
||||
Language: Cpp
|
||||
Standard: c++20
|
||||
|
||||
BasedOnStyle: Chromium
|
||||
|
||||
ColumnLimit: 120
|
||||
AccessModifierOffset: -3
|
||||
IndentWidth: 3
|
||||
ContinuationIndentWidth: 3
|
||||
ConstructorInitializerIndentWidth: 6
|
||||
|
||||
PointerAlignment: Left
|
||||
ReferenceAlignment: Left
|
||||
QualifierAlignment: Left
|
||||
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<botan/internal/.*\.h>'
|
||||
Priority: 3
|
||||
CaseSensitive: false
|
||||
- Regex: '^<botan/.*\.h>'
|
||||
Priority: 2
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*'
|
||||
Priority: 4
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 3
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
CaseSensitive: false
|
||||
|
||||
AttributeMacros: ['BOTAN_FUNC_ISA', 'BOTAN_FUNC_ISA_INLINE', 'BOTAN_FORCE_INLINE']
|
||||
|
||||
BinPackArguments: false
|
||||
BreakStringLiterals: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterComma
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
SpaceBeforeParens: Never
|
||||
IndentPPDirectives: BeforeHash
|
||||
FixNamespaceComments: true
|
||||
SeparateDefinitionBlocks: Always
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
IndentAccessModifiers: true
|
||||
ReflowComments: false
|
||||
RequiresClausePosition: OwnLine
|
||||
IndentRequiresClause: true
|
@ -1,54 +0,0 @@
|
||||
|
||||
# (C) 2022 Jack Lloyd
|
||||
# (C) 2022 René Meusel, Rohde & Schwarz Cybersecurity
|
||||
#
|
||||
# Botan is released under the Simplified BSD License (see license.txt)
|
||||
|
||||
name: Setup Botan Build Agent
|
||||
description: Set up a build agent for building and testing the Botan library
|
||||
|
||||
inputs:
|
||||
target:
|
||||
description: The ci_build.py target going to be built on this agent
|
||||
required: true
|
||||
cache-key:
|
||||
description: The actions/cache key to be used for this runs, caching will be disabled when no key is provided
|
||||
required: false
|
||||
arch:
|
||||
description: Target CPU architecture
|
||||
required: false
|
||||
default: x64
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Build Agent (Windows)
|
||||
run: ${{ github.action_path }}/../../../src/scripts/ci/setup_gh_actions.ps1 "${{ inputs.target }}" "${{ inputs.arch }}"
|
||||
shell: pwsh
|
||||
if: runner.os == 'Windows'
|
||||
- name: Setup Build Agent (Unix-like)
|
||||
run: ${{ github.action_path }}/../../../src/scripts/ci/setup_gh_actions.sh "${{ inputs.target }}" "${{ inputs.arch }}"
|
||||
shell: bash
|
||||
if: runner.os != 'Windows'
|
||||
|
||||
- name: Check Availability of Compiler Cache
|
||||
run: print("::warning ::No compiler cache available, build times might suffer")
|
||||
shell: python
|
||||
if: env.COMPILER_CACHE_LOCATION == '' && inputs.cache-key != ''
|
||||
- uses: actions/cache@v3
|
||||
if: env.COMPILER_CACHE_LOCATION != '' && inputs.cache-key != ''
|
||||
with:
|
||||
path: ${{ env.COMPILER_CACHE_LOCATION }}
|
||||
key: ${{ inputs.cache-key }}-${{ github.run_id }}
|
||||
restore-keys: ${{ inputs.cache-key }}
|
||||
|
||||
- name: Setup Visual Studio Environment
|
||||
uses: egor-tensin/vs-shell@v2
|
||||
with:
|
||||
arch: ${{ env.VSENV_ARCH }} # set by setup_gh_actions.ps1
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
- name: Install Build Dependencies # after setting up Visual Studio Environment
|
||||
run: ${{ github.action_path }}/../../../src/scripts/ci/setup_gh_actions_after_vcvars.ps1 ${{ inputs.target }}
|
||||
shell: pwsh
|
||||
if: runner.os == 'Windows'
|
1
lib/Botan-3.2.0/.github/codecov.yml
vendored
1
lib/Botan-3.2.0/.github/codecov.yml
vendored
@ -1 +0,0 @@
|
||||
../src/scripts/ci/codecov.yml
|
291
lib/Botan-3.2.0/.github/workflows/ci.yml
vendored
291
lib/Botan-3.2.0/.github/workflows/ci.yml
vendored
@ -1,291 +0,0 @@
|
||||
|
||||
# (C) 2020,2022 Jack Lloyd
|
||||
# (C) 2022 René Meusel, Rohde & Schwarz Cybersecurity
|
||||
#
|
||||
# Botan is released under the Simplified BSD License (see license.txt)
|
||||
|
||||
name: ci
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# implicitly all other scopes not listed become none
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# cancel running workflows when new commits are being pushed in pull requests
|
||||
# but not on the master branch
|
||||
concurrency:
|
||||
group: ${{ github.workflow }} @ ${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
name: "Windows"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- target: shared
|
||||
arch: x86_64
|
||||
host_os: windows-2022
|
||||
- target: static
|
||||
arch: x86_64
|
||||
host_os: windows-2022
|
||||
- target: amalgamation
|
||||
arch: x86_64
|
||||
host_os: windows-2022
|
||||
- target: shared
|
||||
arch: x86
|
||||
host_os: windows-2022
|
||||
|
||||
runs-on: ${{ matrix.host_os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: ${{ matrix.host_os }}-msvc-${{ matrix.arch }}-${{ matrix.target }}
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./src/scripts/ci_build.py --cc='msvc' --make-tool='ninja' --cpu='${{ matrix.arch }}' --test-results-dir=junit_results ${{ matrix.target }}
|
||||
|
||||
linux:
|
||||
name: "Linux"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
target: shared
|
||||
- compiler: gcc
|
||||
target: amalgamation
|
||||
- compiler: gcc
|
||||
target: static
|
||||
- compiler: clang
|
||||
target: shared
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: linux-${{ matrix.compiler }}-x86_64-${{ matrix.target }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./src/scripts/ci_build.py --cc='${{ matrix.compiler }}' --test-results-dir=junit_results ${{ matrix.target }}
|
||||
|
||||
macos:
|
||||
name: "macOS"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- target: shared
|
||||
compiler: clang
|
||||
- target: amalgamation
|
||||
compiler: clang
|
||||
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: macos-${{ matrix.compiler }}-x86_64-${{ matrix.target }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./src/scripts/ci_build.py --cc='${{ matrix.compiler }}' --test-results-dir=junit_results ${{ matrix.target }}
|
||||
|
||||
clang-tidy:
|
||||
name: "Clang Tidy"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: clang-tidy
|
||||
cache-key: linux-x86_64-clang-tidy
|
||||
|
||||
- name: Configure Build
|
||||
run: python3 ./configure.py --cc=clang
|
||||
|
||||
- name: Run Clang Tidy
|
||||
run: |
|
||||
./src/scripts/ci/gh_get_changes_in_pr.py $(git rev-parse HEAD) --api-token=${{ secrets.GITHUB_TOKEN }} | \
|
||||
python3 ./src/scripts/dev_tools/run_clang_tidy.py --verbose --take-file-list-from-stdin --export-fixes-dir=clang_tidy_diagnostics
|
||||
|
||||
- name: Display Clang Tidy Results
|
||||
if: failure()
|
||||
run: ./src/scripts/ci/gh_clang_tidy_fixes_in_pr.py clang_tidy_diagnostics
|
||||
|
||||
analysis:
|
||||
name: "Analysis"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- target: coverage
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: sanitizer
|
||||
compiler: msvc
|
||||
host_os: windows-2022
|
||||
make_tool: ninja
|
||||
- target: sanitizer
|
||||
compiler: clang
|
||||
host_os: ubuntu-22.04
|
||||
- target: sanitizer
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: valgrind
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: fuzzers
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: lint
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: format
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
|
||||
runs-on: ${{ matrix.host_os }}
|
||||
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: pbLoTMBxC1DFvbws9WfrzVOvfEdEZTcCS
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
path: ./source
|
||||
|
||||
- name: Fetch BoringSSL fork for BoGo tests
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: randombit/boringssl
|
||||
ref: rene/runner-20230705
|
||||
path: ./boringssl
|
||||
if: matrix.target == 'coverage' || matrix.target == 'sanitizer'
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./source/.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: ${{ matrix.host_os }}-${{ matrix.compiler }}-x86_64-${{ matrix.target }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./source/src/scripts/ci_build.py --root-dir=${{ github.workspace }}/source --build-dir=${{ github.workspace }}/build --boringssl-dir=${{ github.workspace }}/boringssl --cc='${{ matrix.compiler }}' --make-tool='${{ matrix.make_tool }}' --test-results-dir=junit_results ${{ matrix.target }}
|
||||
|
||||
specials:
|
||||
name: "Special"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- target: examples
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: minimized
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: bsi
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
|
||||
runs-on: ${{ matrix.host_os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
path: ./source
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./source/.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: ${{ matrix.host_os }}-${{ matrix.compiler }}-x86_64-${{ matrix.target }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./source/src/scripts/ci_build.py --root-dir=${{ github.workspace }}/source --build-dir=${{ github.workspace }}/build --boringssl-dir=${{ github.workspace }}/boringssl --cc='${{ matrix.compiler }}' --make-tool='${{ matrix.make_tool }}' --test-results-dir=junit_results ${{ matrix.target }}
|
||||
|
||||
x-compile:
|
||||
name: "Cross"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- target: cross-i386
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-arm32
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-arm64
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-ppc64
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-riscv64
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-s390x
|
||||
compiler: gcc
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-android-arm32
|
||||
compiler: clang
|
||||
host_os: ubuntu-22.04
|
||||
- target: cross-android-arm64
|
||||
compiler: clang
|
||||
host_os: ubuntu-22.04
|
||||
- target: static
|
||||
compiler: gcc
|
||||
host_os: windows-2022
|
||||
make_tool: mingw32-make
|
||||
- target: cross-ios-arm64
|
||||
compiler: clang
|
||||
host_os: macos-13
|
||||
- target: emscripten
|
||||
compiler: emcc
|
||||
host_os: macos-13
|
||||
|
||||
runs-on: ${{ matrix.host_os }}
|
||||
|
||||
env:
|
||||
ANDROID_NDK: android-ndk-r26
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
cache-key: ${{ matrix.host_os }}-${{ matrix.compiler }}-xcompile-${{ matrix.target }}
|
||||
|
||||
- name: Build and Test Botan
|
||||
run: python3 ./src/scripts/ci_build.py --cc='${{ matrix.compiler }}' --test-results-dir=junit_results ${{ matrix.target }}
|
29
lib/Botan-3.2.0/.github/workflows/cifuzz.yml
vendored
29
lib/Botan-3.2.0/.github/workflows/cifuzz.yml
vendored
@ -1,29 +0,0 @@
|
||||
name: CIFuzz
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# implicitly all other scopes not listed become none
|
||||
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'botan'
|
||||
dry-run: false
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'botan'
|
||||
fuzz-seconds: 180
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
70
lib/Botan-3.2.0/.github/workflows/codeql.yml
vendored
70
lib/Botan-3.2.0/.github/workflows/codeql.yml
vendored
@ -1,70 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: ["master"]
|
||||
schedule:
|
||||
# runs every day at 4:23 AM UTC
|
||||
- cron: "23 4 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
codeql_cpp:
|
||||
name: C++
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: codeql
|
||||
cache-key: linux-gcc-x86_64-codeql
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: cpp
|
||||
config-file: ./src/configs/codeql.yml
|
||||
|
||||
- name: Build Library
|
||||
run: ./src/scripts/ci_build.py codeql
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: cpp
|
||||
|
||||
codeql_py:
|
||||
name: Python
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: python
|
||||
config-file: ./src/configs/codeql.yml
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: python
|
89
lib/Botan-3.2.0/.github/workflows/nightly.yml
vendored
89
lib/Botan-3.2.0/.github/workflows/nightly.yml
vendored
@ -1,89 +0,0 @@
|
||||
|
||||
# (C) 2023 Jack Lloyd
|
||||
# (C) 2023 Fabian Albert, Rohde & Schwarz Cybersecurity
|
||||
#
|
||||
# Botan is released under the Simplified BSD License (see license.txt)
|
||||
|
||||
name: nightly
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# implicitly all other scopes not listed become none
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# runs every day at 3:23 AM UTC
|
||||
- cron: '23 3 * * *'
|
||||
|
||||
jobs:
|
||||
clang_tidy:
|
||||
name: "clang-tidy"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: clang-tidy
|
||||
cache-key: linux-x86_64-clang-tidy
|
||||
|
||||
- name: Install Boost
|
||||
run: sudo apt-get -qq install libboost-dev
|
||||
|
||||
- name: Configure Build
|
||||
run: python3 ./configure.py --cc=clang --build-targets=shared,cli,tests,examples,bogo_shim --build-fuzzers=test --with-boost --with-sqlite --with-zlib --with-lzma --with-bzip2
|
||||
|
||||
- name: Run Clang Tidy
|
||||
run: python3 ./src/scripts/dev_tools/run_clang_tidy.py --verbose
|
||||
|
||||
valgrind:
|
||||
name: "valgrind"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: valgrind-full
|
||||
cache-key: linux-x86_64-valgrind-full
|
||||
|
||||
- name: Valgrind Checks
|
||||
run: python3 ./src/scripts/ci_build.py --cc=gcc --make-tool=make valgrind-full
|
||||
|
||||
tls_anvil_server_test:
|
||||
name: "TLS-Anvil (server)"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Fetch Botan Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Build Agent
|
||||
uses: ./.github/actions/setup-build-agent
|
||||
with:
|
||||
target: tlsanvil
|
||||
cache-key: linux-x86_64-tlsanvil
|
||||
|
||||
- name: Build and Test Botan Server with TLS-Anvil
|
||||
run: >
|
||||
python3 ./src/scripts/ci/ci_tlsanvil_test.py
|
||||
--botan-dir .
|
||||
--test-target server
|
||||
--parallel $(nproc)
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tls-anvil-server-test-results
|
||||
path: |
|
||||
./TestSuiteResults/
|
||||
./logs/
|
||||
|
||||
- name: Check TLS-Anvil Test Results
|
||||
run: python3 ./src/scripts/ci/ci_tlsanvil_check.py --verbose ./TestSuiteResults
|
98
lib/Botan-3.2.0/.gitignore
vendored
98
lib/Botan-3.2.0/.gitignore
vendored
@ -1,98 +0,0 @@
|
||||
/Makefile
|
||||
CMakeLists.txt*
|
||||
build.ninja
|
||||
.ninja_log
|
||||
libbotan*.so.*
|
||||
*.a
|
||||
*.so
|
||||
*.dylib
|
||||
*.exp
|
||||
*.lib
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.dll
|
||||
*.exe
|
||||
*.manifest
|
||||
build
|
||||
build_deps
|
||||
build.log
|
||||
botan
|
||||
botan-test
|
||||
|
||||
core.*
|
||||
vgcore.*
|
||||
|
||||
# Text file backups (e.g. gedit, joe)
|
||||
*~
|
||||
\#*\#
|
||||
.\#*
|
||||
|
||||
# Editor configuration files (top level)
|
||||
/*.sublime-project
|
||||
/*.sublime-workspace
|
||||
/.editorconfig
|
||||
|
||||
# Archive files
|
||||
*.tgz
|
||||
*.tar
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Patch files
|
||||
*.patch
|
||||
*.diff
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Cache and temporary files
|
||||
*.pyc
|
||||
.DS_Store
|
||||
*.swp
|
||||
/*.cache
|
||||
|
||||
# ctags/etags files
|
||||
/TAGS
|
||||
/tags
|
||||
|
||||
# Amalgamation code
|
||||
botan_all.h
|
||||
botan_all_internal.h
|
||||
botan_all.cpp
|
||||
botan_all_*.cpp
|
||||
|
||||
# Coverage output
|
||||
coverage.info
|
||||
coverage.info.raw
|
||||
coverage/
|
||||
lcov-out/
|
||||
|
||||
/fuzzer_corpus
|
||||
|
||||
# Profiler outputs
|
||||
cachegrind.*
|
||||
callgrind.*
|
||||
|
||||
# Ignore stuff in the top level dir that shouldn't be checked in
|
||||
/*.c
|
||||
/*.cpp
|
||||
/*.h
|
||||
/*.py
|
||||
/*.key
|
||||
/*.pem
|
||||
/*.der
|
||||
/*.ber
|
||||
/*.gpg
|
||||
/*.pub
|
||||
/*.crt
|
||||
/*.txt
|
||||
/*.rst
|
||||
|
||||
# Add back files from the toplevel
|
||||
!/news.rst
|
||||
!/readme.rst
|
||||
!/configure.py
|
||||
!/license.txt
|
||||
|
||||
# cscope
|
||||
cscope.out
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
|
||||
ABI Stability
|
||||
====================
|
||||
|
||||
Botan uses semantic versioning for the API; if API features are added the minor
|
||||
version increases, whereas if API compatibility breaks occur the major version
|
||||
is increased.
|
||||
|
||||
However no guarantees about ABI are made between releases. Maintaining an ABI
|
||||
compatible release in a complex C++ API is exceedingly expensive in development
|
||||
time; just adding a single member variable or virtual function is enough to
|
||||
cause ABI issues.
|
||||
|
||||
If ABI changes, the soname revision will increase to prevent applications from
|
||||
linking against a potentially incompatible version at runtime.
|
||||
|
||||
If you are concerned about long-term ABI issues, considering using the C API
|
||||
instead; this subset *is* ABI stable.
|
||||
|
||||
You can review a report on ABI changes to Botan at
|
||||
https://abi-laboratory.pro/tracker/timeline/botan/
|
@ -1,279 +0,0 @@
|
||||
BigInt
|
||||
========================================
|
||||
|
||||
``BigInt`` is Botan's implementation of a multiple-precision integer. Thanks to
|
||||
C++'s operator overloading features, using ``BigInt`` is often quite similar to
|
||||
using a native integer type. The number of functions related to ``BigInt`` is
|
||||
quite large, and not all of them are documented here. You can find the complete
|
||||
declarations in ``botan/bigint.h`` and ``botan/numthry.h``.
|
||||
|
||||
.. cpp:class:: BigInt
|
||||
|
||||
.. cpp:function:: BigInt()
|
||||
|
||||
Create a BigInt with value zero
|
||||
|
||||
.. cpp:function:: BigInt(uint64_t n)
|
||||
|
||||
Create a BigInt with value *n*
|
||||
|
||||
.. cpp:function:: BigInt(const std::string& str)
|
||||
|
||||
Create a BigInt from a string. By default decimal is expected. With an 0x
|
||||
prefix instead it is treated as hexadecimal.
|
||||
|
||||
.. cpp:function:: BigInt(const uint8_t buf[], size_t length)
|
||||
|
||||
Create a BigInt from a binary array (big-endian encoding).
|
||||
|
||||
.. cpp:function:: BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit = true)
|
||||
|
||||
Create a random BigInt of the specified size.
|
||||
|
||||
.. cpp:function:: BigInt operator+(const BigInt& x, const BigInt& y)
|
||||
|
||||
Add ``x`` and ``y`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator+(const BigInt& x, word y)
|
||||
|
||||
Add ``x`` and ``y`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator+(word x, const BigInt& y)
|
||||
|
||||
Add ``x`` and ``y`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator-(const BigInt& x, const BigInt& y)
|
||||
|
||||
Subtract ``y`` from ``x`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator-(const BigInt& x, word y)
|
||||
|
||||
Subtract ``y`` from ``x`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator*(const BigInt& x, const BigInt& y)
|
||||
|
||||
Multiply ``x`` and ``y`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator/(const BigInt& x, const BigInt& y)
|
||||
|
||||
Divide ``x`` by ``y`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt operator%(const BigInt& x, const BigInt& y)
|
||||
|
||||
Divide ``x`` by ``y`` and return remainder.
|
||||
|
||||
.. cpp:function:: word operator%(const BigInt& x, word y)
|
||||
|
||||
Divide ``x`` by ``y`` and return remainder.
|
||||
|
||||
.. cpp:function:: word operator<<(const BigInt& x, size_t n)
|
||||
|
||||
Left shift ``x`` by ``n`` and return result.
|
||||
|
||||
.. cpp:function:: word operator>>(const BigInt& x, size_t n)
|
||||
|
||||
Right shift ``x`` by ``n`` and return result.
|
||||
|
||||
.. cpp:function:: BigInt& operator+=(const BigInt& y)
|
||||
|
||||
Add y to ``*this``
|
||||
|
||||
.. cpp:function:: BigInt& operator+=(word y)
|
||||
|
||||
Add y to ``*this``
|
||||
|
||||
.. cpp:function:: BigInt& operator-=(const BigInt& y)
|
||||
|
||||
Subtract y from ``*this``
|
||||
|
||||
.. cpp:function:: BigInt& operator-=(word y)
|
||||
|
||||
Subtract y from ``*this``
|
||||
|
||||
.. cpp:function:: BigInt& operator*=(const BigInt& y)
|
||||
|
||||
Multiply ``*this`` with y
|
||||
|
||||
.. cpp:function:: BigInt& operator*=(word y)
|
||||
|
||||
Multiply ``*this`` with y
|
||||
|
||||
.. cpp:function:: BigInt& operator/=(const BigInt& y)
|
||||
|
||||
Divide ``*this`` by y
|
||||
|
||||
.. cpp:function:: BigInt& operator%=(const BigInt& y)
|
||||
|
||||
Divide ``*this`` by y and set ``*this`` to the remainder.
|
||||
|
||||
.. cpp:function:: word operator%=(word y)
|
||||
|
||||
Divide ``*this`` by y and set ``*this`` to the remainder.
|
||||
|
||||
.. cpp:function:: word operator<<=(size_t shift)
|
||||
|
||||
Left shift ``*this`` by *shift* bits
|
||||
|
||||
.. cpp:function:: word operator>>=(size_t shift)
|
||||
|
||||
Right shift ``*this`` by *shift* bits
|
||||
|
||||
.. cpp:function:: BigInt& operator++()
|
||||
|
||||
Increment ``*this`` by 1
|
||||
|
||||
.. cpp:function:: BigInt& operator--()
|
||||
|
||||
Decrement ``*this`` by 1
|
||||
|
||||
.. cpp:function:: BigInt operator++(int)
|
||||
|
||||
Postfix increment ``*this`` by 1
|
||||
|
||||
.. cpp:function:: BigInt operator--(int)
|
||||
|
||||
Postfix decrement ``*this`` by 1
|
||||
|
||||
.. cpp:function:: BigInt operator-() const
|
||||
|
||||
Negation operator
|
||||
|
||||
.. cpp:function:: bool operator !() const
|
||||
|
||||
Return true unless ``*this`` is zero
|
||||
|
||||
.. cpp:function:: void clear()
|
||||
|
||||
Set ``*this`` to zero
|
||||
|
||||
.. cpp:function:: size_t bytes() const
|
||||
|
||||
Return number of bytes need to represent value of ``*this``
|
||||
|
||||
.. cpp:function:: size_t bits() const
|
||||
|
||||
Return number of bits need to represent value of ``*this``
|
||||
|
||||
.. cpp:function:: bool is_even() const
|
||||
|
||||
Return true if ``*this`` is even
|
||||
|
||||
.. cpp:function:: bool is_odd() const
|
||||
|
||||
Return true if ``*this`` is odd
|
||||
|
||||
.. cpp:function:: bool is_nonzero() const
|
||||
|
||||
Return true if ``*this`` is not zero
|
||||
|
||||
.. cpp:function:: bool is_zero() const
|
||||
|
||||
Return true if ``*this`` is zero
|
||||
|
||||
.. cpp:function:: void set_bit(size_t n)
|
||||
|
||||
Set bit *n* of ``*this``
|
||||
|
||||
.. cpp:function:: void clear_bit(size_t n)
|
||||
|
||||
Clear bit *n* of ``*this``
|
||||
|
||||
.. cpp:function:: bool get_bit(size_t n) const
|
||||
|
||||
Get bit *n* of ``*this``
|
||||
|
||||
.. cpp:function:: uint32_t to_u32bit() const
|
||||
|
||||
Return value of ``*this`` as a 32-bit integer, if possible.
|
||||
If the integer is negative or not in range, an exception is thrown.
|
||||
|
||||
.. cpp:function:: bool is_negative() const
|
||||
|
||||
Return true if ``*this`` is negative
|
||||
|
||||
.. cpp:function:: bool is_positive() const
|
||||
|
||||
Return true if ``*this`` is negative
|
||||
|
||||
.. cpp:function:: BigInt abs() const
|
||||
|
||||
Return absolute value of ``*this``
|
||||
|
||||
.. cpp:function:: void binary_encode(uint8_t buf[]) const
|
||||
|
||||
Encode this BigInt as a big-endian integer. The sign is ignored.
|
||||
|
||||
.. cpp:function:: void binary_encode(uint8_t buf[], size_t len) const
|
||||
|
||||
Encode this BigInt as a big-endian integer. The sign is ignored.
|
||||
If ``len`` is less than ``bytes()`` then only the low ``len``
|
||||
bytes are output. If ``len`` is greater than ``bytes()`` then
|
||||
the output is padded with leading zeros.
|
||||
|
||||
.. cpp:function:: void binary_decode(uint8_t buf[])
|
||||
|
||||
Decode this BigInt as a big-endian integer.
|
||||
|
||||
.. cpp:function:: std::string to_dec_string() const
|
||||
|
||||
Encode the integer as a decimal string.
|
||||
|
||||
.. cpp:function:: std::string to_hex_string() const
|
||||
|
||||
Encode the integer as a hexadecimal string.
|
||||
|
||||
Number Theory
|
||||
----------------------------------------
|
||||
|
||||
Number theoretic functions available include:
|
||||
|
||||
.. cpp:function:: BigInt gcd(BigInt x, BigInt y)
|
||||
|
||||
Returns the greatest common divisor of x and y
|
||||
|
||||
.. cpp:function:: BigInt lcm(BigInt x, BigInt y)
|
||||
|
||||
Returns an integer z which is the smallest integer such that z % x
|
||||
== 0 and z % y == 0
|
||||
|
||||
.. cpp:function:: BigInt jacobi(BigInt a, BigInt n)
|
||||
|
||||
Return Jacobi symbol of (a|n).
|
||||
|
||||
.. cpp:function:: BigInt inverse_mod(BigInt x, BigInt m)
|
||||
|
||||
Returns the modular inverse of x modulo m, that is, an integer
|
||||
y such that (x*y) % m == 1. If no such y exists, returns zero.
|
||||
|
||||
.. cpp:function:: BigInt power_mod(BigInt b, BigInt x, BigInt m)
|
||||
|
||||
Returns b to the xth power modulo m. If you are doing many
|
||||
exponentiations with a single fixed modulus, it is faster to use a
|
||||
``Power_Mod`` implementation.
|
||||
|
||||
.. cpp:function:: BigInt ressol(BigInt x, BigInt p)
|
||||
|
||||
Returns the square root modulo a prime, that is, returns a number y
|
||||
such that (y*y) % p == x. Returns -1 if no such integer exists.
|
||||
|
||||
.. cpp:function:: bool is_prime(BigInt n, RandomNumberGenerator& rng, \
|
||||
size_t prob = 56, double is_random = false)
|
||||
|
||||
Test *n* for primality using a probabilistic algorithm (Miller-Rabin). With
|
||||
this algorithm, there is some non-zero probability that true will be returned
|
||||
even if *n* is actually composite. Modifying *prob* allows you to decrease the
|
||||
chance of such a false positive, at the cost of increased runtime. Sufficient
|
||||
tests will be run such that the chance *n* is composite is no more than 1 in
|
||||
2\ :sup:`prob`. Set *is_random* to true if (and only if) *n* was randomly
|
||||
chosen (ie, there is no danger it was chosen maliciously) as far fewer tests
|
||||
are needed in that case.
|
||||
|
||||
.. cpp:function:: BigInt random_prime(RandomNumberGenerator& rng, \
|
||||
size_t bits, \
|
||||
BigInt coprime = 1, \
|
||||
size_t equiv = 1, \
|
||||
size_t equiv_mod = 2)
|
||||
|
||||
Return a random prime number of ``bits`` bits long that is
|
||||
relatively prime to ``coprime``, and equivalent to ``equiv`` modulo
|
||||
``equiv_mod``.
|
@ -1,318 +0,0 @@
|
||||
Block Ciphers
|
||||
=======================
|
||||
|
||||
Block ciphers are a n-bit permutation for some small n, typically 64 or 128
|
||||
bits. They are a cryptographic primitive used to generate higher level
|
||||
operations such as authenticated encryption.
|
||||
|
||||
.. warning::
|
||||
|
||||
In almost all cases, a bare block cipher is not what you should be using.
|
||||
You probably want an authenticated cipher mode instead (see :ref:`cipher_modes`)
|
||||
This interface is used to build higher level operations (such as cipher
|
||||
modes or MACs), or in the very rare situation where ECB is required,
|
||||
eg for compatibility with an existing system.
|
||||
|
||||
.. cpp:class:: BlockCipher
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<BlockCipher> create(const std::string& algo_spec, \
|
||||
const std::string& provider = "")
|
||||
|
||||
Create a new block cipher object, or else return null.
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<BlockCipher> create_or_throw(const std::string& algo_spec, \
|
||||
const std::string& provider = "")
|
||||
|
||||
Like ``create``, except instead of returning null an exception is thrown
|
||||
if the cipher is not known.
|
||||
|
||||
.. cpp:function:: void set_key(const uint8_t* key, size_t length)
|
||||
|
||||
This sets the key to the value specified. Most algorithms only accept keys
|
||||
of certain lengths. If you attempt to call ``set_key`` with a key length
|
||||
that is not supported, the exception ``Invalid_Key_Length`` will be
|
||||
thrown.
|
||||
|
||||
In all cases, ``set_key`` must be called on an object before any data
|
||||
processing (encryption, decryption, etc) is done by that object. If this
|
||||
is not done, an exception will be thrown.
|
||||
thrown.
|
||||
|
||||
.. cpp:function:: bool valid_keylength(size_t length) const
|
||||
|
||||
This function returns true if and only if *length* is a valid keylength for
|
||||
this algorithm.
|
||||
|
||||
.. cpp:function:: size_t minimum_keylength() const
|
||||
|
||||
Return the smallest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: size_t maximum_keylength() const
|
||||
|
||||
Return the largest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: std::string name() const
|
||||
|
||||
Return a human readable name for this algorithm. This is guaranteed to round-trip with
|
||||
``create`` and ``create_or_throw`` calls, ie create("Foo")->name() == "Foo"
|
||||
|
||||
.. cpp:function:: void clear()
|
||||
|
||||
Zero out the key. The key must be reset before the cipher object can be used.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<BlockCipher> new_object() const
|
||||
|
||||
Return a newly allocated BlockCipher object of the same type as this one.
|
||||
The new object is unkeyed.
|
||||
|
||||
.. cpp:function:: size_t block_size() const
|
||||
|
||||
Return the size (in *bytes*) of the cipher.
|
||||
|
||||
.. cpp:function:: size_t parallelism() const
|
||||
|
||||
Return the parallelism underlying this implementation of the cipher. This
|
||||
value can vary across versions and machines. A return value of N means that
|
||||
encrypting or decrypting with N blocks can operate in parallel.
|
||||
|
||||
.. cpp:function:: size_t parallel_bytes() const
|
||||
|
||||
Returns ``parallelism`` multiplied by the block size as well as a small
|
||||
fudge factor. That's because even ciphers that have no implicit parallelism
|
||||
typically see a small speedup for being called with several blocks due to
|
||||
caching effects.
|
||||
|
||||
.. cpp:function:: std::string provider() const
|
||||
|
||||
Return the provider type. Default value is "base" but can be any arbitrary string.
|
||||
Other example values are "sse2", "avx2", "openssl".
|
||||
|
||||
.. cpp:function:: void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
|
||||
|
||||
Encrypt *blocks* blocks of data, taking the input from the array *in* and
|
||||
placing the ciphertext into *out*. The two pointers may be identical, but
|
||||
should not overlap ranges.
|
||||
|
||||
.. cpp:function:: void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
|
||||
|
||||
Decrypt *blocks* blocks of data, taking the input from the array *in* and
|
||||
placing the plaintext into *out*. The two pointers may be identical, but
|
||||
should not overlap ranges.
|
||||
|
||||
.. cpp:function:: void encrypt(const uint8_t in[], uint8_t out[]) const
|
||||
|
||||
Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (in, out, 1).
|
||||
|
||||
.. cpp:function:: void encrypt(uint8_t block[]) const
|
||||
|
||||
Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (block, block, 1)
|
||||
|
||||
.. cpp:function:: void decrypt(const uint8_t in[], uint8_t out[]) const
|
||||
|
||||
Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (in, out, 1)
|
||||
|
||||
.. cpp:function:: void decrypt(uint8_t block[]) const
|
||||
|
||||
Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (block, block, 1)
|
||||
|
||||
.. cpp:function:: template<typename Alloc> void encrypt(std::vector<uint8_t, Alloc>& block) const
|
||||
|
||||
Assumes ``block`` is of a multiple of the block size.
|
||||
|
||||
.. cpp:function:: template<typename Alloc> void decrypt(std::vector<uint8_t, Alloc>& block) const
|
||||
|
||||
Assumes ``block`` is of a multiple of the block size.
|
||||
|
||||
Code Example
|
||||
-----------------
|
||||
|
||||
For sheer demonstrative purposes, the following code encrypts a provided single
|
||||
block of plaintext with AES-256 using two different keys.
|
||||
|
||||
.. literalinclude:: /../src/examples/aes.cpp
|
||||
:language: cpp
|
||||
|
||||
Available Ciphers
|
||||
---------------------
|
||||
|
||||
Botan includes a number of block ciphers that are specific to particular countries, as
|
||||
well as a few that are included mostly due to their use in specific protocols such as PGP
|
||||
but not widely used elsewhere. If you are developing new code and have no particular
|
||||
opinion, use AES-256. If you desire an alternative to AES, consider Serpent, SHACAL2 or
|
||||
Threefish.
|
||||
|
||||
.. warning:: Avoid any 64-bit block cipher in new designs. There are
|
||||
combinatoric issues that affect any 64-bit cipher that render it
|
||||
insecure when large amounts of data are processed.
|
||||
|
||||
AES
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Comes in three variants, AES-128, AES-192, and AES-256.
|
||||
|
||||
The standard 128-bit block cipher. Many modern platforms offer hardware
|
||||
acceleration. However, on platforms without hardware support, AES
|
||||
implementations typically are vulnerable to side channel attacks. For x86
|
||||
systems with SSSE3 but without AES-NI, Botan has an implementation which avoids
|
||||
known side channels.
|
||||
|
||||
Available if ``BOTAN_HAS_AES`` is defined.
|
||||
|
||||
ARIA
|
||||
~~~~~~
|
||||
|
||||
South Korean cipher used in industry there. No reason to use it otherwise.
|
||||
|
||||
Available if ``BOTAN_HAS_ARIA`` is defined.
|
||||
|
||||
Blowfish
|
||||
~~~~~~~~~
|
||||
|
||||
A 64-bit cipher popular in the pre-AES era. Very slow key setup. Also used (with
|
||||
bcrypt) for password hashing.
|
||||
|
||||
Available if ``BOTAN_HAS_BLOWFISH`` is defined.
|
||||
|
||||
CAST-128
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A 64-bit cipher, commonly used in OpenPGP.
|
||||
|
||||
Available if ``BOTAN_HAS_CAST128`` is defined.
|
||||
|
||||
Camellia
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Comes in three variants, Camellia-128, Camellia-192, and Camellia-256.
|
||||
|
||||
A Japanese design standardized by ISO, NESSIE and CRYPTREC.
|
||||
Rarely used outside of Japan.
|
||||
|
||||
Available if ``BOTAN_HAS_CAMELLIA`` is defined.
|
||||
|
||||
Cascade
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Creates a block cipher cascade, where each block is encrypted by two ciphers
|
||||
with independent keys. Useful if you're very paranoid. In practice any single
|
||||
good cipher (such as Serpent, SHACAL2, or AES-256) is more than sufficient.
|
||||
|
||||
Available if ``BOTAN_HAS_CASCADE`` is defined.
|
||||
|
||||
DES and 3DES
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Originally designed by IBM and NSA in the 1970s. Today, DES's 56-bit key renders
|
||||
it insecure to any well-resourced attacker. 3DES extends the key length,
|
||||
and is still thought to be secure, modulo the limitation of a 64-bit block.
|
||||
All are somewhat common in some industries such as finance. Avoid in new code.
|
||||
|
||||
Available if ``BOTAN_HAS_DES`` is defined.
|
||||
|
||||
GOST-28147-89
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Aka "Magma". An old 64-bit Russian cipher. Possible security issues, avoid
|
||||
unless compatibility is needed.
|
||||
|
||||
Available if ``BOTAN_HAS_GOST_28147_89`` is defined.
|
||||
|
||||
.. warning::
|
||||
Support for this cipher is deprecated and will be removed in a future major release.
|
||||
|
||||
IDEA
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An older but still unbroken 64-bit cipher with a 128-bit key. Somewhat common
|
||||
due to its use in PGP. Avoid in new designs.
|
||||
|
||||
Available if ``BOTAN_HAS_IDEA`` is defined.
|
||||
|
||||
Kuznyechik
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
Newer Russian national cipher, also known as GOST R 34.12-2015 or "Grasshopper".
|
||||
|
||||
.. warning::
|
||||
|
||||
The sbox of this cipher is supposedly random, but was found to have a
|
||||
mathematical structure which is exceedingly unlikely to have occured by
|
||||
chance. This may indicate the existence of a backdoor or other issue. Avoid
|
||||
using this cipher unless strictly required.
|
||||
|
||||
Available if ``BOTAN_HAS_KUZNYECHIK`` is defined.
|
||||
|
||||
|
||||
Lion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A "block cipher construction" which can encrypt blocks of nearly arbitrary
|
||||
length. Built from a stream cipher and a hash function. Useful in certain
|
||||
protocols where being able to encrypt large or arbitrary length blocks is
|
||||
necessary.
|
||||
|
||||
Available if ``BOTAN_HAS_LION`` is defined.
|
||||
|
||||
Noekeon
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A fast 128-bit cipher by the designers of AES. Easily secured against side
|
||||
channels. Quite obscure however.
|
||||
|
||||
Available if ``BOTAN_HAS_NOEKEON`` is defined.
|
||||
|
||||
.. warning::
|
||||
Noekeon support is deprecated and will be removed in a future major release.
|
||||
|
||||
SEED
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A older South Korean cipher, widely used in industry there. No reason to choose it otherwise.
|
||||
|
||||
Available if ``BOTAN_HAS_SEED`` is defined.
|
||||
|
||||
SHACAL2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The 256-bit block cipher used inside SHA-256. Accepts up to a 512-bit key.
|
||||
Fast, especially when SIMD or SHA-2 acceleration instructions are available.
|
||||
Standardized by NESSIE but otherwise obscure.
|
||||
|
||||
Available if ``BOTAN_HAS_SHACAL2`` is defined.
|
||||
|
||||
SM4
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A 128-bit Chinese national cipher, required for use in certain commercial
|
||||
applications in China. Quite slow. Probably no reason to use it outside of legal
|
||||
requirements.
|
||||
|
||||
Available if ``BOTAN_HAS_SM4`` is defined.
|
||||
|
||||
Serpent
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An AES contender. Widely considered the most conservative design. Fairly slow
|
||||
unless SIMD instructions are available.
|
||||
|
||||
Available if ``BOTAN_HAS_SERPENT`` is defined.
|
||||
|
||||
Threefish-512
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A 512-bit tweakable block cipher that was used in the Skein hash function.
|
||||
Very fast on 64-bit processors.
|
||||
|
||||
Available if ``BOTAN_HAS_THREEFISH_512`` is defined.
|
||||
|
||||
Twofish
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A 128-bit block cipher that was one of the AES finalists. Has a somewhat complicated key
|
||||
setup and a "kitchen sink" design.
|
||||
|
||||
Available if ``BOTAN_HAS_TWOFISH`` is defined.
|
@ -1,377 +0,0 @@
|
||||
.. _cipher_modes:
|
||||
|
||||
Cipher Modes
|
||||
=====================
|
||||
|
||||
A block cipher by itself, is only able to securely encrypt a single data block.
|
||||
To be able to securely encrypt data of arbitrary length, a mode of operation
|
||||
applies the block cipher's single block operation repeatedly to encrypt
|
||||
an entire message.
|
||||
|
||||
All cipher mode implementations are are derived from the base class
|
||||
:cpp:class:`Cipher_Mode`, which is declared in ``botan/cipher_mode.h``.
|
||||
|
||||
.. warning::
|
||||
Using an unauthenticted cipher mode without combining it with a
|
||||
:ref:`mac` is insecure. Prefer using an :ref:`aead`.
|
||||
|
||||
.. cpp:class:: Cipher_Mode
|
||||
|
||||
.. cpp:function:: void set_key(const uint8_t* key, size_t length)
|
||||
|
||||
Set the symmetric key to be used.
|
||||
|
||||
.. cpp:function:: bool valid_keylength(size_t length) const
|
||||
|
||||
This function returns true if and only if *length* is a valid
|
||||
keylength for the algorithm.
|
||||
|
||||
.. cpp:function:: size_t minimum_keylength() const
|
||||
|
||||
Return the smallest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: size_t maximum_keylength() const
|
||||
|
||||
Return the largest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: size_t default_nonce_length() const
|
||||
|
||||
Return the default (preferable) nonce size for this cipher mode.
|
||||
|
||||
.. cpp:function:: bool valid_nonce_length(size_t nonce_len) const
|
||||
|
||||
Return true if *nonce_len* is a valid length for a nonce with this
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: bool authenticated() const
|
||||
|
||||
Return true if this cipher mode is authenticated
|
||||
|
||||
.. cpp:function:: size_t tag_size() const
|
||||
|
||||
Return the length in bytes of the authentication tag this algorithm
|
||||
generates. If the mode is not authenticated, this will return 0. If the mode
|
||||
is authenticated, it will return some positive value (typically somewhere
|
||||
between 8 and 16).
|
||||
|
||||
.. cpp:function:: void clear()
|
||||
|
||||
Clear all internal state. The object will act exactly like one which was
|
||||
just allocated.
|
||||
|
||||
.. cpp:function:: void reset()
|
||||
|
||||
Reset all message state. For example if you called :cpp:func:`start_msg`,
|
||||
then :cpp:func:`process` to process some ciphertext, but then encounter an
|
||||
IO error and must abandon the current message, you can call `reset`. The
|
||||
object will retain the key (unlike calling :cpp:func:`clear` which also
|
||||
resets the key) but the nonce and current message state will be erased.
|
||||
|
||||
.. cpp:function:: void start_msg(const uint8_t* nonce, size_t nonce_len)
|
||||
|
||||
Set up for processing a new message. This function must be called with a new
|
||||
random value for each message. For almost all modes (excepting SIV), if the
|
||||
same nonce is ever used twice with the same key, the encryption scheme loses
|
||||
its confidentiality and/or authenticity properties.
|
||||
|
||||
.. cpp:function:: void start(const std::vector<uint8_t> nonce)
|
||||
|
||||
Acts like :cpp:func:`start_msg`\ (nonce.data(), nonce.size()).
|
||||
|
||||
.. cpp:function:: void start(const uint8_t* nonce, size_t nonce_len)
|
||||
|
||||
Acts like :cpp:func:`start_msg`\ (nonce, nonce_len).
|
||||
|
||||
.. cpp:function:: virtual size_t update_granularity() const
|
||||
|
||||
The :cpp:class:`Cipher_Mode` interface requires message processing in multiples of the block size.
|
||||
Returns size of required blocks to update. Will return 1 if the mode implementation
|
||||
does not require buffering.
|
||||
|
||||
.. cpp:function:: virtual size_t ideal_granularity() const
|
||||
|
||||
Returns a multiple of update_granularity sized for ideal performance.
|
||||
|
||||
In fact this is not truly the "ideal" buffer size but just reflects the
|
||||
smallest possible buffer that can reasonably take advantage of available
|
||||
parallelism (due to SIMD execution, etc). If you are concerned about
|
||||
performance, it may be advisable to take this return value and scale it to
|
||||
approximately 4 KB, and use buffers of that size.
|
||||
|
||||
.. cpp:function:: virtual size_t process(uint8_t* msg, size_t msg_len)
|
||||
|
||||
Process msg in place and returns the number of bytes written. *msg* must
|
||||
be a multiple of :cpp:func:`update_granularity`.
|
||||
|
||||
.. cpp:function:: void update(secure_vector<uint8_t>& buffer, size_t offset = 0)
|
||||
|
||||
Continue processing a message in the buffer in place. The passed buffer's
|
||||
size must be a multiple of :cpp:func:`update_granularity`. The first
|
||||
*offset* bytes of the buffer will be ignored.
|
||||
|
||||
.. cpp:function:: size_t minimum_final_size() const
|
||||
|
||||
Returns the minimum size needed for :cpp:func:`finish`. This is used for
|
||||
example when processing an AEAD message, to ensure the tag is available. In
|
||||
that case, the encryption side will return 0 (since the tag is generated,
|
||||
rather than being provided) while the decryption mode will return the size
|
||||
of the tag.
|
||||
|
||||
.. cpp:function:: void finish(secure_vector<uint8_t>& final_block, size_t offset = 0)
|
||||
|
||||
Finalize the message processing with a final block of at least :cpp:func:`minimum_final_size` size.
|
||||
The first *offset* bytes of the passed final block will be ignored.
|
||||
|
||||
Code Example
|
||||
---------------------
|
||||
|
||||
The following code encrypts the specified plaintext using AES-128/CBC
|
||||
with PKCS#7 padding.
|
||||
|
||||
.. warning::
|
||||
This example ignores the requirement to authenticate the ciphertext
|
||||
|
||||
.. note::
|
||||
Simply replacing the string "AES-128/CBC/PKCS7" string in the example below
|
||||
with "AES-128/GCM" suffices to use authenticated encryption.
|
||||
|
||||
.. literalinclude:: /../src/examples/aes_cbc.cpp
|
||||
:language: cpp
|
||||
|
||||
|
||||
Available Unauthenticated Cipher Modes
|
||||
-----------------------------------------
|
||||
|
||||
.. note::
|
||||
CTR and OFB modes are also implemented, but these are treated as
|
||||
:cpp:class:`Stream_Cipher`\s instead.
|
||||
|
||||
CBC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_MODE_CBC`` is defined.
|
||||
|
||||
CBC requires the plaintext be padded using a reversible rule. The following
|
||||
padding schemes are implemented
|
||||
|
||||
PKCS#7 (RFC5652)
|
||||
The last byte in the padded block defines the padding length p, the remaining padding bytes are set to p as well.
|
||||
ANSI X9.23
|
||||
The last byte in the padded block defines the padding length, the remaining padding is filled with 0x00.
|
||||
OneAndZeros (ISO/IEC 7816-4)
|
||||
The first padding byte is set to 0x80, the remaining padding bytes are set to 0x00.
|
||||
|
||||
Ciphertext stealing (CTS) is also implemented. This scheme allows the
|
||||
ciphertext to have the same length as the plaintext, however using CTS
|
||||
requires the input be at least one full block plus one byte. It is
|
||||
also less commonly implemented.
|
||||
|
||||
.. warning::
|
||||
Using CBC with padding without an authentication mode exposes your
|
||||
application to CBC padding oracle attacks, which allow recovering
|
||||
the plaintext of arbitrary messages. Always pair CBC with a MAC such
|
||||
as HMAC (or, preferably, use an AEAD such as GCM).
|
||||
|
||||
CFB
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_MODE_CFB`` is defined.
|
||||
|
||||
CFB uses a block cipher to create a self-synchronizing stream cipher. It is used
|
||||
for example in the OpenPGP protocol. There is no reason to prefer it, as it has
|
||||
worse performance characteristics than modes such as CTR or CBC.
|
||||
|
||||
XTS
|
||||
~~~~~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_MODE_XTS`` is defined.
|
||||
|
||||
XTS is a mode specialized for encrypting disk or database storage
|
||||
where ciphertext expansion is not possible. XTS requires all inputs be
|
||||
at least one full block (16 bytes for AES), however for any acceptable
|
||||
input length, there is no ciphertext expansion.
|
||||
|
||||
.. _aead:
|
||||
|
||||
AEAD Mode
|
||||
---------------------------
|
||||
|
||||
AEAD (Authenticated Encryption with Associated Data) modes provide message
|
||||
encryption, message authentication, and the ability to authenticate additional
|
||||
data that is not included in the ciphertext (such as a sequence number or
|
||||
header). It is a subclass of :cpp:class:`Cipher_Mode`.
|
||||
|
||||
.. cpp:class:: AEAD_Mode
|
||||
|
||||
.. cpp:function:: void set_key(const SymmetricKey& key)
|
||||
|
||||
Set the key
|
||||
|
||||
.. cpp:function:: Key_Length_Specification key_spec() const
|
||||
|
||||
Return the key length specification
|
||||
|
||||
.. cpp:function:: void set_associated_data(const uint8_t ad[], size_t ad_len)
|
||||
|
||||
Set any associated data for this message. For maximum portability between
|
||||
different modes, this must be called after :cpp:func:`set_key` and before
|
||||
:cpp:func:`start`.
|
||||
|
||||
If the associated data does not change, it is not necessary to call this
|
||||
function more than once, even across multiple calls to :cpp:func:`start`
|
||||
and :cpp:func:`finish`.
|
||||
|
||||
.. cpp:function:: void start(const uint8_t nonce[], size_t nonce_len)
|
||||
|
||||
Start processing a message, using *nonce* as the unique per-message
|
||||
value. It does not need to be random, simply unique (per key).
|
||||
|
||||
.. warning::
|
||||
With almost all AEADs, if the same nonce is ever used to encrypt two
|
||||
different messages under the same key, all security is lost. If
|
||||
reliably generating unique nonces is difficult in your environment,
|
||||
use SIV mode which retains security even if nonces are repeated.
|
||||
|
||||
.. cpp:function:: void update(secure_vector<uint8_t>& buffer, size_t offset = 0)
|
||||
|
||||
Continue processing a message. The *buffer* is an in/out parameter and
|
||||
may be resized. In particular, some modes require that all input be
|
||||
consumed before any output is produced; with these modes, *buffer* will
|
||||
be returned empty.
|
||||
|
||||
On input, the buffer must be sized in blocks of size
|
||||
:cpp:func:`update_granularity`. For instance if the update granularity
|
||||
was 64, then *buffer* could be 64, 128, 192, ... bytes.
|
||||
|
||||
The first *offset* bytes of *buffer* will be ignored (this allows in
|
||||
place processing of a buffer that contains an initial plaintext header)
|
||||
|
||||
.. cpp:function:: void finish(secure_vector<uint8_t>& buffer, size_t offset = 0)
|
||||
|
||||
Complete processing a message with a final input of *buffer*, which is
|
||||
treated the same as with :cpp:func:`update`. It must contain at least
|
||||
:cpp:func:`final_minimum_size` bytes.
|
||||
|
||||
Note that if you have the entire message in hand, calling finish without
|
||||
ever calling update is both efficient and convenient.
|
||||
|
||||
.. note::
|
||||
|
||||
During decryption, if the supplied authentication tag does not
|
||||
validate, finish will throw an instance of Invalid_Authentication_Tag
|
||||
(aka Integrity_Failure, which was the name for this exception in
|
||||
versions before 2.10, a typedef is included for compatability).
|
||||
|
||||
If this occurs, all plaintext previously output via calls to update
|
||||
must be destroyed and not used in any way that an attacker could
|
||||
observe the effects of. This could be anything from echoing the
|
||||
plaintext back (perhaps in an error message), or by making an external
|
||||
RPC whose destination or contents depend on the plaintext. The only
|
||||
thing you can do is buffer it, and in the event of an invalid tag,
|
||||
erase the previously decrypted content from memory.
|
||||
|
||||
One simply way to assure this could never happen is to never
|
||||
call update, and instead always marshal the entire message
|
||||
into a single buffer and call finish on it when decrypting.
|
||||
|
||||
.. cpp:function:: size_t update_granularity() const
|
||||
|
||||
The AEAD interface requires :cpp:func:`update` be called with blocks of
|
||||
this size. This will be 1, if the mode can process any length inputs.
|
||||
|
||||
.. cpp:function:: size_t final_minimum_size() const
|
||||
|
||||
The AEAD interface requires :cpp:func:`finish` be called with at least
|
||||
this many bytes (which may be zero, or greater than
|
||||
:cpp:func:`update_granularity`)
|
||||
|
||||
.. cpp:function:: bool valid_nonce_length(size_t nonce_len) const
|
||||
|
||||
Returns true if *nonce_len* is a valid nonce length for this scheme. For
|
||||
EAX and GCM, any length nonces are allowed. OCB allows any value between
|
||||
8 and 15 bytes.
|
||||
|
||||
.. cpp:function:: size_t default_nonce_length() const
|
||||
|
||||
Returns a reasonable length for the nonce, typically either 96
|
||||
bits, or the only supported length for modes which don't
|
||||
support 96 bit nonces.
|
||||
|
||||
|
||||
Available AEAD Modes
|
||||
-------------------------
|
||||
|
||||
If in doubt about what to use, pick ChaCha20Poly1305, AES-256/GCM, or AES-256/SIV.
|
||||
Both ChaCha20Poly1305 and AES with GCM are widely implemented. SIV is somewhat
|
||||
more obscure (and is slower than either GCM or ChaCha20Poly1305), but has
|
||||
excellent security properties.
|
||||
|
||||
ChaCha20Poly1305
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_CHACHA20_POLY1305`` is defined.
|
||||
|
||||
Unlike the other AEADs which are based on block ciphers, this mode is based on
|
||||
the ChaCha stream cipher and the Poly1305 authentication code. It is very fast
|
||||
on all modern platforms.
|
||||
|
||||
ChaCha20Poly1305 supports 64-bit, 96-bit, and (since 2.8) 192-bit nonces. 64-bit nonces
|
||||
are the "classic" ChaCha20Poly1305 design. 96-bit nonces are used by the IETF standard
|
||||
version of ChaCha20Poly1305. And 192-bit nonces is the XChaCha20Poly1305 construction,
|
||||
which is somewhat less common.
|
||||
|
||||
For best interop use the IETF version with 96-bit nonces. However 96 bits is small enough
|
||||
that it can be dangerous to generate nonces randomly if more than ~ 2^32 messages are
|
||||
encrypted under a single key, since if a nonce is ever reused ChaCha20Poly1305 becomes
|
||||
insecure. It is better to use a counter for the nonce in this case.
|
||||
|
||||
If you are encrypting many messages under a single key and cannot maintain a counter for
|
||||
the nonce, prefer XChaCha20Poly1305 since a 192 bit nonce is large enough that randomly
|
||||
chosen nonces are extremely unlikely to repeat.
|
||||
|
||||
GCM
|
||||
~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_GCM`` is defined.
|
||||
|
||||
NIST standard, commonly used. Requires a 128-bit block cipher. Fairly slow,
|
||||
unless hardware support for carryless multiplies is available.
|
||||
|
||||
OCB
|
||||
~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_OCB`` is defined.
|
||||
|
||||
A block cipher based AEAD. Supports 128-bit, 256-bit and 512-bit block ciphers.
|
||||
This mode is very fast and easily secured against side channels. Adoption has
|
||||
been poor because until 2021 it was patented in the United States. The patent
|
||||
was allowed to lapse in early 2021.
|
||||
|
||||
EAX
|
||||
~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_EAX`` is defined.
|
||||
|
||||
A secure composition of CTR mode and CMAC. Supports 128-bit, 256-bit and 512-bit
|
||||
block ciphers.
|
||||
|
||||
SIV
|
||||
~~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_SIV`` is defined.
|
||||
|
||||
Requires a 128-bit block cipher. Unlike other AEADs, SIV is "misuse resistant";
|
||||
if a nonce is repeated, SIV retains security, with the exception that if the
|
||||
same nonce is used to encrypt the same message multiple times, an attacker can
|
||||
detect the fact that the message was duplicated (this is simply because if both
|
||||
the nonce and the message are reused, SIV will output identical ciphertexts).
|
||||
|
||||
CCM
|
||||
~~~~~
|
||||
|
||||
Available if ``BOTAN_HAS_AEAD_CCM`` is defined.
|
||||
|
||||
A composition of CTR mode and CBC-MAC. Requires a 128-bit block cipher. This is
|
||||
a NIST standard mode, but that is about all to recommend it. Prefer EAX.
|
@ -1,97 +0,0 @@
|
||||
Lossless Data Compression
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some lossless data compression algorithms are available in botan, currently all
|
||||
via third party libraries - these include zlib (including deflate and gzip
|
||||
formats), bzip2, and lzma. Support for these must be enabled at build time;
|
||||
you can check for them using the macros ``BOTAN_HAS_ZLIB``, ``BOTAN_HAS_BZIP2``,
|
||||
and ``BOTAN_HAS_LZMA``.
|
||||
|
||||
.. note::
|
||||
You should always compress *before* you encrypt, because encryption seeks to
|
||||
hide the redundancy that compression is supposed to try to find and remove.
|
||||
|
||||
Compression is done through the ``Compression_Algorithm`` and
|
||||
``Decompression_Algorithm`` classes, both defined in `compression.h`
|
||||
|
||||
Compression and decompression both work in three stages: starting a
|
||||
message (``start``), continuing to process it (``update``), and then
|
||||
finally completing processing the stream (``finish``).
|
||||
|
||||
.. cpp:class:: Compression_Algorithm
|
||||
|
||||
.. cpp:function:: void start(size_t level)
|
||||
|
||||
Initialize the compression engine. This must be done before calling
|
||||
``update`` or ``finish``. The meaning of the `level` parameter varies by
|
||||
the algorithm but generally takes a value between 1 and 9, with higher
|
||||
values implying typically better compression from and more memory and/or
|
||||
CPU time consumed by the compression process. The decompressor can always
|
||||
handle input from any compressor.
|
||||
|
||||
.. cpp:function:: void update(secure_vector<uint8_t>& buf, \
|
||||
size_t offset = 0, bool flush = false)
|
||||
|
||||
Compress the material in the in/out parameter ``buf``. The leading
|
||||
``offset`` bytes of ``buf`` are ignored and remain untouched; this can be
|
||||
useful for ignoring packet headers. If ``flush`` is true, the
|
||||
compression state is flushed, allowing the decompressor to recover the
|
||||
entire message up to this point without having the see the rest of the
|
||||
compressed stream.
|
||||
|
||||
.. cpp::function:: void finish(secure_vector<uint8_t>& buf, size_t offset = 0)
|
||||
|
||||
Finish compressing a message. The ``buf`` and ``offset`` parameters are
|
||||
treated as in ``update``. It is acceptable to call ``start`` followed by
|
||||
``finish`` with the entire message, without any intervening call to
|
||||
``update``.
|
||||
|
||||
.. cpp:class:: Decompression_Algorithm
|
||||
|
||||
.. cpp:function:: void start()
|
||||
|
||||
Initialize the decompression engine. This must be done before calling
|
||||
``update`` or ``finish``. No level is provided here; the decompressor
|
||||
can accept input generated by any compression parameters.
|
||||
|
||||
.. cpp:function:: void update(secure_vector<uint8_t>& buf, \
|
||||
size_t offset = 0)
|
||||
|
||||
Decompress the material in the in/out parameter ``buf``. The leading
|
||||
``offset`` bytes of ``buf`` are ignored and remain untouched; this can be
|
||||
useful for ignoring packet headers.
|
||||
|
||||
This function may throw if the data seems to be invalid.
|
||||
|
||||
.. cpp::function:: void finish(secure_vector<uint8_t>& buf, size_t offset = 0)
|
||||
|
||||
Finish decompressing a message. The ``buf`` and ``offset`` parameters are
|
||||
treated as in ``update``. It is acceptable to call ``start`` followed by
|
||||
``finish`` with the entire message, without any intervening call to
|
||||
``update``.
|
||||
|
||||
This function may throw if the data seems to be invalid.
|
||||
|
||||
The easiest way to get a compressor is via the functions
|
||||
``Compression_Algorithm::create`` and
|
||||
``Decompression_Algorithm::create`` which both accept a string
|
||||
argument which can take values include `zlib` (raw zlib with no
|
||||
checksum), `deflate` (zlib's deflate format), `gzip`, `bz2`, and
|
||||
`lzma`. A null pointer will be returned if the algorithm is
|
||||
unavailable.
|
||||
|
||||
Two older functions for this are
|
||||
|
||||
.. cpp:function:: Compression_Algorithm* make_compressor(std::string type)
|
||||
.. cpp:function:: Decompression_Algorithm* make_decompressor(std::string type)
|
||||
|
||||
which call the relevant ``create`` function and then ``release`` the
|
||||
returned ``unique_ptr``. Avoid these in new code.
|
||||
|
||||
To use a compression algorithm in a `Pipe` use the adapter types
|
||||
`Compression_Filter` and `Decompression_Filter` from `comp_filter.h`. The
|
||||
constructors of both filters take a `std::string` argument (passed to
|
||||
`make_compressor` or `make_decompressor`), the compression filter also takes a
|
||||
`level` parameter. Finally both constructors have a parameter `buf_sz` which
|
||||
specifies the size of the internal buffer that will be used - inputs will be
|
||||
broken into blocks of this size. The default is 4096.
|
@ -1,41 +0,0 @@
|
||||
|
||||
API Reference
|
||||
===================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
footguns
|
||||
versions
|
||||
secmem
|
||||
rng
|
||||
hash
|
||||
block_cipher
|
||||
stream_ciphers
|
||||
message_auth_codes
|
||||
cipher_modes
|
||||
pubkey
|
||||
x509
|
||||
tls
|
||||
credentials_manager
|
||||
bigint
|
||||
kdf
|
||||
pbkdf
|
||||
keywrap
|
||||
passhash
|
||||
cryptobox
|
||||
srp
|
||||
psk_db
|
||||
filters
|
||||
fpe
|
||||
tss
|
||||
ecc
|
||||
compression
|
||||
pkcs11
|
||||
tpm
|
||||
otp
|
||||
roughtime
|
||||
zfec
|
||||
ffi
|
||||
env_vars
|
||||
python
|
@ -1,197 +0,0 @@
|
||||
|
||||
Credentials Manager
|
||||
==================================================
|
||||
|
||||
A ``Credentials_Manager`` is a way to abstract how the application
|
||||
stores credentials. The main user is the :doc:`tls` implementation.
|
||||
|
||||
.. cpp:class:: Credentials_Manager
|
||||
|
||||
.. cpp:function:: std::vector<Certificate_Store*> \
|
||||
trusted_certificate_authorities( \
|
||||
const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Return the list of certificate stores, each of which is assumed
|
||||
to contain (only) trusted certificate authorities. The
|
||||
``Credentials_Manager`` retains ownership of the
|
||||
Certificate_Store pointers.
|
||||
|
||||
.. note::
|
||||
|
||||
It would have been a better API to return a vector of
|
||||
``shared_ptr`` here. This may change in a future major release.
|
||||
|
||||
When *type* is "tls-client", *context* will be the hostname of
|
||||
the server, or empty if the hostname is not known. This allows
|
||||
using a different set of certificate stores in different contexts,
|
||||
for example using the system certificate store unless contacting
|
||||
one particular server which uses a cert issued by an internal CA.
|
||||
|
||||
When *type* is "tls-server", the *context* will again be the
|
||||
hostname of the server, or empty if the client did not send a
|
||||
server name indicator. For TLS servers, these CAs are the ones
|
||||
trusted for signing of client certificates. If you do not want
|
||||
the TLS server to ask for a client cert,
|
||||
``trusted_certificate_authorities`` should return an empty list
|
||||
for *type* "tls-server".
|
||||
|
||||
The default implementation returns an empty list.
|
||||
|
||||
.. cpp:function:: std::vector<X509_Certificate> find_cert_chain( \
|
||||
const std::vector<std::string>& cert_key_types, \
|
||||
const std::vector<X509_DN>& acceptable_CAs, \
|
||||
const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Return the certificate chain to use to identify ourselves. The
|
||||
``acceptable_CAs`` parameter gives a list of CAs the peer trusts.
|
||||
This may be empty.
|
||||
|
||||
.. warning::
|
||||
If this function returns a certificate that is not one of the
|
||||
types given in ``cert_key_types`` confusing handshake
|
||||
failures will result.
|
||||
|
||||
.. cpp:function:: std::vector<X509_Certificate> cert_chain( \
|
||||
const std::vector<std::string>& cert_key_types, \
|
||||
const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Return the certificate chain to use to identify ourselves. Starting in
|
||||
2.5, prefer ``find_cert_chain`` which additionally provides the CA list.
|
||||
|
||||
.. cpp:function:: std::vector<X509_Certificate> cert_chain_single_type( \
|
||||
const std::string& cert_key_type, \
|
||||
const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Return the certificate chain to use to identifier ourselves, if
|
||||
we have one of type *cert_key_type* and we would like to use a
|
||||
certificate in this *type*/*context*.
|
||||
|
||||
For servers *type* will be "tls-server" and the *context* will
|
||||
be the server name that the client requested via SNI (or empty,
|
||||
if the client did not send SNI).
|
||||
|
||||
.. warning::
|
||||
|
||||
To avoid cross-protocol attacks it is recommended that if a server
|
||||
receives an SNI request for a name it does not expect, it should close
|
||||
the connection with an alert. This can be done by throwing an exception
|
||||
from the implementation of this function.
|
||||
|
||||
.. cpp:function:: std::shared_ptr<Private_Key> private_key_for(const X509_Certificate& cert, \
|
||||
const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Return a shared pointer to the private key for this certificate. The
|
||||
*cert* will be the leaf cert of a chain returned previously by
|
||||
``cert_chain`` or ``cert_chain_single_type``.
|
||||
|
||||
In versions before 1.11.34, there was an additional function on `Credentials_Manager`
|
||||
|
||||
.. cpp::function:: void verify_certificate_chain( \
|
||||
const std::string& type, \
|
||||
const std::string& hostname, \
|
||||
const std::vector<X509_Certificate>& cert_chain)
|
||||
|
||||
This function has been replaced by `TLS::Callbacks::tls_verify_cert_chain`.
|
||||
|
||||
SRP Authentication
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``Credentials_Manager`` contains the hooks used by TLS clients and
|
||||
servers for SRP authentication.
|
||||
|
||||
.. note::
|
||||
|
||||
Support for TLS-SRP is deprecated, and will be removed in a future
|
||||
major release. When that occurs these APIs will be removed. Prefer
|
||||
instead performing a standard TLS handshake, then perform a PAKE
|
||||
authentication inside of (and cryptographically bound to) the TLS
|
||||
channel.
|
||||
|
||||
.. cpp:function:: bool attempt_srp(const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Returns if we should consider using SRP for authentication
|
||||
|
||||
.. cpp:function:: std::string srp_identifier(const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Returns the SRP identifier we'd like to use (used by client)
|
||||
|
||||
.. cpp:function:: std::string srp_password(const std::string& type, \
|
||||
const std::string& context, \
|
||||
const std::string& identifier)
|
||||
|
||||
Returns the password for *identifier* (used by client)
|
||||
|
||||
.. cpp:function:: bool srp_verifier(const std::string& type, \
|
||||
const std::string& context, \
|
||||
const std::string& identifier, \
|
||||
std::string& group_name, \
|
||||
BigInt& verifier, \
|
||||
std::vector<uint8_t>& salt, \
|
||||
bool generate_fake_on_unknown)
|
||||
|
||||
Returns the SRP verifier information for *identifier* (used by server)
|
||||
|
||||
Preshared Keys
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
TLS supports the use of pre shared keys for authentication.
|
||||
|
||||
.. cpp:function:: SymmetricKey psk(const std::string& type, \
|
||||
const std::string& context, \
|
||||
const std::string& identity)
|
||||
|
||||
Return a symmetric key for use with *identity*
|
||||
|
||||
One important special case for ``psk`` is where *type* is
|
||||
"tls-server", *context* is "session-ticket" and *identity* is an
|
||||
empty string. If a key is returned for this case, a TLS server
|
||||
will offer session tickets to clients who can use them, and the
|
||||
returned key will be used to encrypt the ticket. The server is
|
||||
allowed to change the key at any time (though changing the key
|
||||
means old session tickets can no longer be used for resumption,
|
||||
forcing a full re-handshake when the client next connects). One
|
||||
simple approach to add support for session tickets in your server
|
||||
is to generate a random key the first time ``psk`` is called to
|
||||
retrieve the session ticket key, cache it for later use in the
|
||||
``Credentials_Manager``, and simply let it be thrown away when the
|
||||
process terminates. See :rfc:`4507` for more information about TLS
|
||||
session tickets.
|
||||
|
||||
A similar special case exists for DTLS cookie verification. In
|
||||
this case *type* will be "tls-server" and *context* is
|
||||
"dtls-cookie-secret". If no key is returned, then DTLS cookies are
|
||||
not used. Similar to the session ticket key, the DTLS cookie
|
||||
secret can be chosen during server startup and rotated at any time
|
||||
with no ill effect.
|
||||
|
||||
.. warning::
|
||||
|
||||
If DTLS cookies are not used then the server is prone to be
|
||||
abused as a DoS amplifier, where the attacker sends a
|
||||
relatively small client hello in a UDP packet with a forged
|
||||
return address, and then the server replies to the victim with
|
||||
several messages that are larger. This not only hides the
|
||||
attackers address from the victim, but increases their
|
||||
effective bandwidth. This is not an issue when using DTLS over
|
||||
SCTP or TCP.
|
||||
|
||||
.. cpp:function:: std::string psk_identity_hint(const std::string& type, \
|
||||
const std::string& context)
|
||||
|
||||
Returns an identity hint which may be provided to the client. This
|
||||
can help a client understand what PSK to use.
|
||||
|
||||
.. cpp:function:: std::string psk_identity(const std::string& type, \
|
||||
const std::string& context, \
|
||||
const std::string& identity_hint)
|
||||
|
||||
Returns the identity we would like to use given this *type* and
|
||||
*context* and the optional *identity_hint*. Not all servers or
|
||||
protocols will provide a hint.
|
@ -1,34 +0,0 @@
|
||||
|
||||
Cryptobox
|
||||
========================================
|
||||
|
||||
Encryption using a passphrase
|
||||
----------------------------------------
|
||||
|
||||
.. versionadded:: 1.8.6
|
||||
|
||||
.. deprecated:: 3.0
|
||||
|
||||
This is a set of simple routines that encrypt some data using a
|
||||
passphrase. There are defined in the header `cryptobox.h`, inside
|
||||
namespace `Botan::CryptoBox`.
|
||||
|
||||
It generates cipher and MAC keys using 8192 iterations of PBKDF2 with
|
||||
HMAC(SHA-512), then encrypts using Serpent in CTR mode and authenticates using a
|
||||
HMAC(SHA-512) mac of the ciphertext, truncated to 160 bits.
|
||||
|
||||
.. cpp:function:: std::string encrypt(const uint8_t input[], size_t input_len, \
|
||||
const std::string& passphrase, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
Encrypt the contents using *passphrase*.
|
||||
|
||||
.. cpp:function:: std::string decrypt(const uint8_t input[], size_t input_len, \
|
||||
const std::string& passphrase)
|
||||
|
||||
Decrypts something encrypted with encrypt.
|
||||
|
||||
.. cpp:function:: std::string decrypt(const std::string& input, \
|
||||
const std::string& passphrase)
|
||||
|
||||
Decrypts something encrypted with encrypt.
|
@ -1,284 +0,0 @@
|
||||
Elliptic Curve Operations
|
||||
============================
|
||||
|
||||
In addition to high level operations for signatures, key agreement,
|
||||
and message encryption using elliptic curve cryptography, the library
|
||||
contains lower level interfaces for performing operations such as
|
||||
elliptic curve point multiplication.
|
||||
|
||||
Only curves over prime fields are supported.
|
||||
|
||||
Many of these functions take a workspace, either a vector of words or
|
||||
a vector of BigInts. These are used to minimize memory allocations
|
||||
during common operations.
|
||||
|
||||
.. warning::
|
||||
You should only use these interfaces if you know what you are doing.
|
||||
|
||||
.. cpp:class:: EC_Group
|
||||
|
||||
.. cpp:function:: EC_Group(const OID& oid)
|
||||
|
||||
Initialize an ``EC_Group`` using an OID referencing the curve
|
||||
parameters.
|
||||
|
||||
.. cpp:function:: EC_Group(const std::string& name)
|
||||
|
||||
Initialize an ``EC_Group`` using a name or OID (for example
|
||||
"secp256r1", or "1.2.840.10045.3.1.7")
|
||||
|
||||
.. cpp:function:: EC_Group(const BigInt& p, \
|
||||
const BigInt& a, \
|
||||
const BigInt& b, \
|
||||
const BigInt& base_x, \
|
||||
const BigInt& base_y, \
|
||||
const BigInt& order, \
|
||||
const BigInt& cofactor, \
|
||||
const OID& oid = OID())
|
||||
|
||||
Initialize an elliptic curve group from the relevant parameters. This
|
||||
is used for example to create custom (application-specific) curves.
|
||||
|
||||
.. cpp:function:: EC_Group(const std::vector<uint8_t>& ber_encoding)
|
||||
|
||||
Initialize an ``EC_Group`` by decoding a DER encoded parameter block.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> DER_encode(EC_Group_Encoding form) const
|
||||
|
||||
Return the DER encoding of this group.
|
||||
|
||||
.. cpp:function:: std::string PEM_encode() const
|
||||
|
||||
Return the PEM encoding of this group (base64 of DER encoding plus
|
||||
header/trailer).
|
||||
|
||||
.. cpp:function:: bool a_is_minus_3() const
|
||||
|
||||
Return true if the ``a`` parameter is congruent to -3 mod p.
|
||||
|
||||
.. cpp:function:: bool a_is_zero() const
|
||||
|
||||
Return true if the ``a`` parameter is congruent to 0 mod p.
|
||||
|
||||
.. cpp:function:: size_t get_p_bits() const
|
||||
|
||||
Return size of the prime in bits.
|
||||
|
||||
.. cpp:function:: size_t get_p_bytes() const
|
||||
|
||||
Return size of the prime in bytes.
|
||||
|
||||
.. cpp:function:: size_t get_order_bits() const
|
||||
|
||||
Return size of the group order in bits.
|
||||
|
||||
.. cpp:function:: size_t get_order_bytes() const
|
||||
|
||||
Return size of the group order in bytes.
|
||||
|
||||
.. cpp:function:: const BigInt& get_p() const
|
||||
|
||||
Return the prime modulus.
|
||||
|
||||
.. cpp:function:: const BigInt& get_a() const
|
||||
|
||||
Return the ``a`` parameter of the elliptic curve equation.
|
||||
|
||||
.. cpp:function:: const BigInt& get_b() const
|
||||
|
||||
Return the ``b`` parameter of the elliptic curve equation.
|
||||
|
||||
.. cpp:function:: const EC_Point& get_base_point() const
|
||||
|
||||
Return the groups base point element.
|
||||
|
||||
.. cpp:function:: const BigInt& get_g_x() const
|
||||
|
||||
Return the x coordinate of the base point element.
|
||||
|
||||
.. cpp:function:: const BigInt& get_g_y() const
|
||||
|
||||
Return the y coordinate of the base point element.
|
||||
|
||||
.. cpp:function:: const BigInt& get_order() const
|
||||
|
||||
Return the order of the group generated by the base point.
|
||||
|
||||
.. cpp:function:: const BigInt& get_cofactor() const
|
||||
|
||||
Return the cofactor of the curve. In most cases this will be 1.
|
||||
|
||||
.. cpp:function:: BigInt mod_order(const BigInt& x) const
|
||||
|
||||
Reduce argument ``x`` modulo the curve order.
|
||||
|
||||
.. cpp:function:: BigInt inverse_mod_order(const BigInt& x) const
|
||||
|
||||
Return inverse of argument ``x`` modulo the curve order.
|
||||
|
||||
.. cpp:function:: BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const
|
||||
|
||||
Multiply ``x`` and ``y`` and reduce the result modulo the curve order.
|
||||
|
||||
.. cpp:function:: bool verify_public_element(const EC_Point& y) const
|
||||
|
||||
Return true if ``y`` seems to be a valid group element.
|
||||
|
||||
.. cpp:function:: const OID& get_curve_oid() const
|
||||
|
||||
Return the OID used to identify the curve. May be empty.
|
||||
|
||||
.. cpp:function:: EC_Point point(const BigInt& x, const BigInt& y) const
|
||||
|
||||
Create and return a point with affine elements ``x`` and ``y``. Note
|
||||
this function *does not* verify that ``x`` and ``y`` satisfy the curve
|
||||
equation.
|
||||
|
||||
.. cpp:function:: EC_Point point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const
|
||||
|
||||
Multi-exponentiation. Returns base_point*x + pt*y. Not constant time.
|
||||
(Ordinarily used for signature verification.)
|
||||
|
||||
.. cpp:function:: EC_Point blinded_base_point_multiply(const BigInt& k, \
|
||||
RandomNumberGenerator& rng, \
|
||||
std::vector<BigInt>& ws) const
|
||||
|
||||
Return ``base_point*k`` in a way that attempts to resist side channels.
|
||||
|
||||
.. cpp:function:: BigInt blinded_base_point_multiply_x(const BigInt& k, \
|
||||
RandomNumberGenerator& rng, \
|
||||
std::vector<BigInt>& ws) const
|
||||
|
||||
Like `blinded_base_point_multiply` but returns only the x coordinate.
|
||||
|
||||
.. cpp:function:: EC_Point blinded_var_point_multiply(const EC_Point& point, \
|
||||
const BigInt& k, \
|
||||
RandomNumberGenerator& rng, \
|
||||
std::vector<BigInt>& ws) const
|
||||
|
||||
Return ``point*k`` in a way that attempts to resist side channels.
|
||||
|
||||
.. cpp:function:: BigInt random_scalar(RandomNumberGenerator& rng) const
|
||||
|
||||
Return a random scalar (ie an integer between 1 and the group order).
|
||||
|
||||
.. cpp:function:: EC_Point zero_point() const
|
||||
|
||||
Return the zero point (aka the point at infinity).
|
||||
|
||||
.. cpp:function:: EC_Point OS2ECP(const uint8_t bits[], size_t len) const
|
||||
|
||||
Decode a point from the binary encoding. This function verifies that
|
||||
the decoded point is a valid element on the curve.
|
||||
|
||||
.. cpp:function:: bool verify_group(RandomNumberGenerator& rng, bool strong = false) const
|
||||
|
||||
Attempt to verify the group seems valid.
|
||||
|
||||
.. cpp:function:: static const std::set<std::string>& known_named_groups()
|
||||
|
||||
Return a list of known groups, ie groups for which ``EC_Group(name)``
|
||||
will succeed.
|
||||
|
||||
.. cpp:class:: EC_Point
|
||||
|
||||
Stores elliptic curve points in Jacobian representation.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> encode(EC_Point::Compression_Type format) const
|
||||
|
||||
Encode a point in a way that can later be decoded with `EC_Group::OS2ECP`.
|
||||
|
||||
.. cpp:function:: EC_Point& operator+=(const EC_Point& rhs)
|
||||
|
||||
Point addition.
|
||||
|
||||
.. cpp:function:: EC_Point& operator-=(const EC_Point& rhs)
|
||||
|
||||
Point subtraction.
|
||||
|
||||
.. cpp:function:: EC_Point& operator*=(const BigInt& scalar)
|
||||
|
||||
Point multiplication using Montgomery ladder.
|
||||
|
||||
.. warning::
|
||||
Prefer the blinded functions in ``EC_Group``
|
||||
|
||||
.. cpp:function:: EC_Point& negate()
|
||||
|
||||
Negate this point.
|
||||
|
||||
.. cpp:function:: BigInt get_affine_x() const
|
||||
|
||||
Return the affine ``x`` coordinate of the point.
|
||||
|
||||
.. cpp:function:: BigInt get_affine_y() const
|
||||
|
||||
Return the affine ``y`` coordinate of the point.
|
||||
|
||||
.. cpp:function:: void force_affine()
|
||||
|
||||
Convert the point to its equivalent affine coordinates. Throws
|
||||
if this is the point at infinity.
|
||||
|
||||
.. cpp:function:: static void force_all_affine(std::vector<EC_Point>& points, \
|
||||
secure_vector<word>& ws)
|
||||
|
||||
Force several points to be affine at once. Uses Montgomery's
|
||||
trick to reduce number of inversions required, so this is much
|
||||
faster than calling ``force_affine`` on each point in sequence.
|
||||
|
||||
.. cpp:function:: bool is_affine() const
|
||||
|
||||
Return true if this point is in affine coordinates.
|
||||
|
||||
.. cpp:function:: bool is_zero() const
|
||||
|
||||
Return true if this point is zero (aka point at infinity).
|
||||
|
||||
.. cpp:function:: bool on_the_curve() const
|
||||
|
||||
Return true if this point is on the curve.
|
||||
|
||||
.. cpp:function:: void randomize_repr(RandomNumberGenerator& rng)
|
||||
|
||||
Randomize the point representation.
|
||||
|
||||
.. cpp:function:: bool operator==(const EC_Point& other) const
|
||||
|
||||
Point equality. This compares the affine representations.
|
||||
|
||||
.. cpp:function:: void add(const EC_Point& other, std::vector<BigInt>& workspace)
|
||||
|
||||
Point addition, taking a workspace.
|
||||
|
||||
.. cpp:function:: void add_affine(const EC_Point& other, std::vector<BigInt>& workspace)
|
||||
|
||||
Mixed (Jacobian+affine) addition, taking a workspace.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function assumes that ``other`` is affine, if this is
|
||||
not correct the result will be invalid.
|
||||
|
||||
.. cpp:function:: void mult2(std::vector<BigInt>& workspace)
|
||||
|
||||
Point doubling.
|
||||
|
||||
.. cpp:function:: void mult2i(size_t i, std::vector<BigInt>& workspace)
|
||||
|
||||
Repeated point doubling.
|
||||
|
||||
.. cpp:function:: EC_Point plus(const EC_Point& other, std::vector<BigInt>& workspace) const
|
||||
|
||||
Point addition, returning the result.
|
||||
|
||||
.. cpp:function:: EC_Point double_of(std::vector<BigInt>& workspace) const
|
||||
|
||||
Point doubling, returning the result.
|
||||
|
||||
.. cpp:function:: EC_Point zero() const
|
||||
|
||||
Return the point at infinity
|
||||
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
.. _env_vars:
|
||||
|
||||
Environment Variables
|
||||
======================
|
||||
|
||||
Certain environment variables can affect or tune the behavior of the
|
||||
library. The variables and their behavior are described here.
|
||||
|
||||
* ``BOTAN_THREAD_POOL_SIZE`` controls the number of threads which will be
|
||||
created for a thread pool used for some purposes within the library. If not
|
||||
set, or set to 0, then it defaults to the number of CPUs available on the
|
||||
system. If it is set to the string "none" then the thread pool is disabled;
|
||||
instead all work passed to the thread pool will be executed immediately
|
||||
by the calling thread.
|
||||
|
||||
As of version 3.2.0, on MinGW the thread pool is by default disabled, due to a
|
||||
bug which causes deadlock on application shutdown. Enabling the pool can be
|
||||
explicitly requested by setting ``BOTAN_THREAD_POOL_SIZE`` to an integer
|
||||
value.
|
||||
|
||||
* ``BOTAN_MLOCK_POOL_SIZE`` controls the total amount of memory, in bytes, which
|
||||
will be locked in memory using ``mlock`` or ``VirtualLock`` and managed in a
|
||||
memory pool. This should be a multiple of the system page size. If set to
|
||||
``0``, then the memory pool is disabled.
|
||||
|
||||
* ``BOTAN_FFI_PRINT_EXCEPTIONS`` if this variable is set (to any value), then
|
||||
if an exception is caught by the FFI layer, before returning an error code, it
|
||||
will print the text message of the exception to stderr. This is primarily
|
||||
intended for debugging.
|
||||
|
||||
* ``BOTAN_CLEAR_CPUID``: this variable can be set to a comma-separated list of
|
||||
CPUID fields to ignore. For example setting ``BOTAN_CLEAR_CPUID=avx2,avx512``
|
||||
will cause AVX2 and AVX-512 codepaths to be avoided. Note that disabling basic
|
||||
features (notably NEON or SSE2/SSSE3) can cause other higher level features
|
||||
like AES-NI to also become disabled.
|
File diff suppressed because it is too large
Load Diff
@ -1,733 +0,0 @@
|
||||
|
||||
Pipe/Filter Message Processing
|
||||
========================================
|
||||
|
||||
.. note::
|
||||
|
||||
The system described below provides a message processing system with a
|
||||
straightforward API. However it makes many extra memory copies and
|
||||
allocations than would otherwise be required, and also tends to make
|
||||
applications using it somewhat opaque because it is not obvious what this or
|
||||
that Pipe& object actually does (type of operation, number of messages
|
||||
output (if any!), and so on), whereas using say a HashFunction or AEAD_Mode
|
||||
provides a much better idea in the code of what operation is occurring.
|
||||
|
||||
This filter interface is no longer used within the library itself
|
||||
(outside a few dusty corners) and will likely not see any further major
|
||||
development. However it will remain included because the API is often
|
||||
convenient and many applications use it.
|
||||
|
||||
Many common uses of cryptography involve processing one or more
|
||||
streams of data. Botan provides services that make setting up data
|
||||
flows through various operations, such as compression, encryption, and
|
||||
base64 encoding. Each of these operations is implemented in what are
|
||||
called *filters* in Botan. A set of filters are created and placed into
|
||||
a *pipe*, and information "flows" through the pipe until it reaches
|
||||
the end, where the output is collected for retrieval. If you're
|
||||
familiar with the Unix shell environment, this design will sound quite
|
||||
familiar.
|
||||
|
||||
Here is an example that uses a pipe to base64 encode some strings::
|
||||
|
||||
Pipe pipe(new Base64_Encoder); // pipe owns the pointer
|
||||
pipe.start_msg();
|
||||
pipe.write("message 1");
|
||||
pipe.end_msg(); // flushes buffers, increments message number
|
||||
|
||||
// process_msg(x) is start_msg() && write(x) && end_msg()
|
||||
pipe.process_msg("message2");
|
||||
|
||||
std::string m1 = pipe.read_all_as_string(0); // "message1"
|
||||
std::string m2 = pipe.read_all_as_string(1); // "message2"
|
||||
|
||||
Byte streams in the pipe are grouped into messages; blocks of data that
|
||||
are processed in an identical fashion (ie, with the same sequence of
|
||||
filter operations). Messages are delimited by calls to ``start_msg``
|
||||
and ``end_msg``. Each message in a pipe has its own identifier, which
|
||||
currently is an integer that increments up from zero.
|
||||
|
||||
The ``Base64_Encoder`` was allocated using ``new``; but where was it
|
||||
deallocated? When a filter object is passed to a ``Pipe``, the pipe
|
||||
takes ownership of the object, and will deallocate it when it is no
|
||||
longer needed.
|
||||
|
||||
There are two different ways to make use of messages. One is to send
|
||||
several messages through a ``Pipe`` without changing the ``Pipe``
|
||||
configuration, so you end up with a sequence of messages; one use of
|
||||
this would be to send a sequence of identically encrypted UDP packets,
|
||||
for example (note that the *data* need not be identical; it is just
|
||||
that each is encrypted, encoded, signed, etc in an identical
|
||||
fashion). Another is to change the filters that are used in the
|
||||
``Pipe`` between each message, by adding or removing filters;
|
||||
functions that let you do this are documented in the Pipe API section.
|
||||
|
||||
Botan has about 40 filters that perform different operations on data.
|
||||
Here's code that uses one of them to encrypt a string with AES::
|
||||
|
||||
AutoSeeded_RNG rng,
|
||||
SymmetricKey key(rng, 16); // a random 128-bit key
|
||||
InitializationVector iv(rng, 16); // a random 128-bit IV
|
||||
|
||||
// The algorithm we want is specified by a string
|
||||
Pipe pipe(get_cipher("AES-128/CBC", key, iv, Cipher_Dir::Encryption));
|
||||
|
||||
pipe.process_msg("secrets");
|
||||
pipe.process_msg("more secrets");
|
||||
|
||||
secure_vector<uint8_t> c1 = pipe.read_all(0);
|
||||
|
||||
uint8_t c2[4096] = { 0 };
|
||||
size_t got_out = pipe.read(c2, sizeof(c2), 1);
|
||||
// use c2[0...got_out]
|
||||
|
||||
Note the use of ``AutoSeeded_RNG``, which is a random number
|
||||
generator. If you want to, you can explicitly set up the random number
|
||||
generators and entropy sources you want to, however for 99% of cases
|
||||
``AutoSeeded_RNG`` is preferable.
|
||||
|
||||
``Pipe`` also has convenience methods for dealing with ``std::iostream``.
|
||||
Here is an example of this, using the bzip2 compression filter::
|
||||
|
||||
std::ifstream in("data.bin", std::ios::binary)
|
||||
std::ofstream out("data.bin.bz2", std::ios::binary)
|
||||
|
||||
Pipe pipe(new Compression_Filter("bzip2", 9));
|
||||
|
||||
pipe.start_msg();
|
||||
in >> pipe;
|
||||
pipe.end_msg();
|
||||
out << pipe;
|
||||
|
||||
However there is a hitch to the code above; the complete contents of
|
||||
the compressed data will be held in memory until the entire message
|
||||
has been compressed, at which time the statement ``out << pipe`` is
|
||||
executed, and the data is freed as it is read from the pipe and
|
||||
written to the file. But if the file is very large, we might not have
|
||||
enough physical memory (or even enough virtual memory!) for that to be
|
||||
practical. So instead of storing the compressed data in the pipe for
|
||||
reading it out later, we divert it directly to the file::
|
||||
|
||||
std::ifstream in("data.bin", std::ios::binary)
|
||||
std::ofstream out("data.bin.bz2", std::ios::binary)
|
||||
|
||||
Pipe pipe(new Compression_Filter("bzip2", 9), new DataSink_Stream(out));
|
||||
|
||||
pipe.start_msg();
|
||||
in >> pipe;
|
||||
pipe.end_msg();
|
||||
|
||||
This is the first code we've seen so far that uses more than one
|
||||
filter in a pipe. The output of the compressor is sent to the
|
||||
``DataSink_Stream``. Anything written to a ``DataSink_Stream`` is
|
||||
written to a file; the filter produces no output. As soon as the
|
||||
compression algorithm finishes up a block of data, it will send it
|
||||
along to the sink filter, which will immediately write it to the
|
||||
stream; if you were to call ``pipe.read_all()`` after
|
||||
``pipe.end_msg()``, you'd get an empty vector out. This is
|
||||
particularly useful for cases where you are processing a large amount
|
||||
of data, as it means you don't have to store everything in memory at
|
||||
once.
|
||||
|
||||
Here's an example using two computational filters::
|
||||
|
||||
AutoSeeded_RNG rng,
|
||||
SymmetricKey key(rng, 32);
|
||||
InitializationVector iv(rng, 16);
|
||||
|
||||
Pipe encryptor(get_cipher("AES/CBC/PKCS7", key, iv, Cipher_Dir::Encryption),
|
||||
new Base64_Encoder);
|
||||
|
||||
encryptor.start_msg();
|
||||
file >> encryptor;
|
||||
encryptor.end_msg(); // flush buffers, complete computations
|
||||
std::cout << encryptor;
|
||||
|
||||
You can read from a pipe while you are still writing to it, which
|
||||
allows you to bound the amount of memory that is in use at any one
|
||||
time. A common idiom for this is::
|
||||
|
||||
pipe.start_msg();
|
||||
std::vector<uint8_t> buffer(4096); // arbitrary size
|
||||
while(infile.good())
|
||||
{
|
||||
infile.read((char*)&buffer[0], buffer.size());
|
||||
const size_t got_from_infile = infile.gcount();
|
||||
pipe.write(buffer, got_from_infile);
|
||||
|
||||
if(infile.eof())
|
||||
pipe.end_msg();
|
||||
|
||||
while(pipe.remaining() > 0)
|
||||
{
|
||||
const size_t buffered = pipe.read(buffer, buffer.size());
|
||||
outfile.write((const char*)&buffer[0], buffered);
|
||||
}
|
||||
}
|
||||
if(infile.bad() || (infile.fail() && !infile.eof()))
|
||||
throw Some_Exception();
|
||||
|
||||
Fork
|
||||
---------------------------------
|
||||
|
||||
It is common that you might receive some data and want to perform more
|
||||
than one operation on it (ie, encrypt it with Serpent and calculate
|
||||
the SHA-256 hash of the plaintext at the same time). That's where
|
||||
``Fork`` comes in. ``Fork`` is a filter that takes input and passes it
|
||||
on to *one or more* filters that are attached to it. ``Fork`` changes
|
||||
the nature of the pipe system completely: instead of being a linked
|
||||
list, it becomes a tree or acyclic graph.
|
||||
|
||||
Each filter in the fork is given its own output buffer, and thus its
|
||||
own message. For example, if you had previously written two messages
|
||||
into a pipe, then you start a new one with a fork that has three
|
||||
paths of filter's inside it, you add three new messages to the
|
||||
pipe. The data you put into the pipe is duplicated and sent
|
||||
into each set of filter and the eventual output is placed into a
|
||||
dedicated message slot in the pipe.
|
||||
|
||||
Messages in the pipe are allocated in a depth-first manner. This is only
|
||||
interesting if you are using more than one fork in a single pipe.
|
||||
As an example, consider the following::
|
||||
|
||||
Pipe pipe(new Fork(
|
||||
new Fork(
|
||||
new Base64_Encoder,
|
||||
new Fork(
|
||||
NULL,
|
||||
new Base64_Encoder
|
||||
)
|
||||
),
|
||||
new Hex_Encoder
|
||||
)
|
||||
);
|
||||
|
||||
In this case, message 0 will be the output of the first
|
||||
``Base64_Encoder``, message 1 will be a copy of the input (see below
|
||||
for how fork interprets NULL pointers), message 2 will be the output
|
||||
of the second ``Base64_Encoder``, and message 3 will be the output of
|
||||
the ``Hex_Encoder``. This results in message numbers being allocated
|
||||
in a top to bottom fashion, when looked at on the screen. However,
|
||||
note that there could be potential for bugs if this is not
|
||||
anticipated. For example, if your code is passed a filter, and you
|
||||
assume it is a "normal" one that only uses one message, your message
|
||||
offsets would be wrong, leading to some confusion during output.
|
||||
|
||||
If Fork's first argument is a null pointer, but a later argument is
|
||||
not, then Fork will feed a copy of its input directly through. Here's
|
||||
a case where that is useful::
|
||||
|
||||
// have std::string ciphertext, auth_code, key, iv, mac_key;
|
||||
|
||||
Pipe pipe(new Base64_Decoder,
|
||||
get_cipher("AES-128", key, iv, Cipher_Dir::Decryption),
|
||||
new Fork(
|
||||
0, // this message gets plaintext
|
||||
new MAC_Filter("HMAC(SHA-1)", mac_key)
|
||||
)
|
||||
);
|
||||
|
||||
pipe.process_msg(ciphertext);
|
||||
std::string plaintext = pipe.read_all_as_string(0);
|
||||
secure_vector<uint8_t> mac = pipe.read_all(1);
|
||||
|
||||
if(mac != auth_code)
|
||||
error();
|
||||
|
||||
Here we wanted to not only decrypt the message, but send the decrypted
|
||||
text through an additional computation, in order to compute the
|
||||
authentication code.
|
||||
|
||||
Any filters that are attached to the pipe after the fork are
|
||||
implicitly attached onto the first branch created by the fork. For
|
||||
example, let's say you created this pipe::
|
||||
|
||||
Pipe pipe(new Fork(new Hash_Filter("SHA-256"),
|
||||
new Hash_Filter("SHA-512")),
|
||||
new Hex_Encoder);
|
||||
|
||||
And then called ``start_msg``, inserted some data, then
|
||||
``end_msg``. Then ``pipe`` would contain two messages. The first one
|
||||
(message number 0) would contain the SHA-256 sum of the input in hex
|
||||
encoded form, and the other would contain the SHA-512 sum of the input
|
||||
in raw binary. In many situations you'll want to perform a sequence of
|
||||
operations on multiple branches of the fork; in which case, use
|
||||
the filter described in :ref:`chain`.
|
||||
|
||||
There is also a ``Threaded_Fork`` which acts the same as ``Fork``,
|
||||
except it runs each of the filters in its own thread.
|
||||
|
||||
.. _chain:
|
||||
|
||||
Chain
|
||||
---------------------------------
|
||||
|
||||
A ``Chain`` filter creates a chain of filters and encapsulates them
|
||||
inside a single filter (itself). This allows a sequence of filters to
|
||||
become a single filter, to be passed into or out of a function, or to
|
||||
a ``Fork`` constructor.
|
||||
|
||||
You can call ``Chain``'s constructor with up to four ``Filter``
|
||||
pointers (they will be added in order), or with an array of filter
|
||||
pointers and a ``size_t`` that tells ``Chain`` how many filters are in
|
||||
the array (again, they will be attached in order). Here's the example
|
||||
from the last section, using chain instead of relying on the implicit
|
||||
pass through the other version used::
|
||||
|
||||
Pipe pipe(new Fork(
|
||||
new Chain(new Hash_Filter("SHA-256"), new Hex_Encoder),
|
||||
new Hash_Filter("SHA-512")
|
||||
)
|
||||
);
|
||||
|
||||
Sources and Sinks
|
||||
----------------------------------------
|
||||
|
||||
Data Sources
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A ``DataSource`` is a simple abstraction for a thing that stores
|
||||
bytes. This type is used heavily in the areas of the API related to
|
||||
ASN.1 encoding/decoding. The following types are ``DataSource``:
|
||||
``Pipe``, ``SecureQueue``, and a couple of special purpose ones:
|
||||
``DataSource_Memory`` and ``DataSource_Stream``.
|
||||
|
||||
You can create a ``DataSource_Memory`` with an array of bytes and a
|
||||
length field. The object will make a copy of the data, so you don't
|
||||
have to worry about keeping that memory allocated. This is mostly for
|
||||
internal use, but if it comes in handy, feel free to use it.
|
||||
|
||||
A ``DataSource_Stream`` is probably more useful than the memory based
|
||||
one. Its constructors take either a ``std::istream`` or a
|
||||
``std::string``. If it's a stream, the data source will use the
|
||||
``istream`` to satisfy read requests (this is particularly useful to
|
||||
use with ``std::cin``). If the string version is used, it will attempt
|
||||
to open up a file with that name and read from it.
|
||||
|
||||
Data Sinks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A ``DataSink`` (in ``data_snk.h``) is a ``Filter`` that takes
|
||||
arbitrary amounts of input, and produces no output. This means it's
|
||||
doing something with the data outside the realm of what
|
||||
``Filter``/``Pipe`` can handle, for example, writing it to a file
|
||||
(which is what the ``DataSink_Stream`` does). There is no need for
|
||||
``DataSink``s that write to a ``std::string`` or memory buffer,
|
||||
because ``Pipe`` can handle that by itself.
|
||||
|
||||
Here's a quick example of using a ``DataSink``, which encrypts
|
||||
``in.txt`` and sends the output to ``out.txt``. There is
|
||||
no explicit output operation; the writing of ``out.txt`` is
|
||||
implicit::
|
||||
|
||||
DataSource_Stream in("in.txt");
|
||||
Pipe pipe(get_cipher("AES-128/CTR-BE", key, iv),
|
||||
new DataSink_Stream("out.txt"));
|
||||
pipe.process_msg(in);
|
||||
|
||||
A real advantage of this is that even if "in.txt" is large, only as
|
||||
much memory is needed for internal I/O buffers will be used.
|
||||
|
||||
The Pipe API
|
||||
---------------------------------
|
||||
|
||||
Initializing Pipe
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default, ``Pipe`` will do nothing at all; any input placed into the
|
||||
``Pipe`` will be read back unchanged. Obviously, this has limited
|
||||
utility, and presumably you want to use one or more filters to somehow
|
||||
process the data. First, you can choose a set of filters to initialize
|
||||
the ``Pipe`` via the constructor. You can pass it either a set of up
|
||||
to four filter pointers, or a pre-defined array and a length::
|
||||
|
||||
Pipe pipe1(new Filter1(/*args*/), new Filter2(/*args*/),
|
||||
new Filter3(/*args*/), new Filter4(/*args*/));
|
||||
Pipe pipe2(new Filter1(/*args*/), new Filter2(/*args*/));
|
||||
|
||||
Filter* filters[5] = {
|
||||
new Filter1(/*args*/), new Filter2(/*args*/), new Filter3(/*args*/),
|
||||
new Filter4(/*args*/), new Filter5(/*args*/) /* more if desired... */
|
||||
};
|
||||
Pipe pipe3(filters, 5);
|
||||
|
||||
This is by far the most common way to initialize a ``Pipe``. However,
|
||||
occasionally a more flexible initialization strategy is necessary;
|
||||
this is supported by 4 member functions. These functions may only be
|
||||
used while the pipe in question is not in use; that is, either before
|
||||
calling ``start_msg``, or after ``end_msg`` has been called (and no
|
||||
new calls to ``start_msg`` have been made yet).
|
||||
|
||||
.. cpp:function:: void Pipe::prepend(Filter* filter)
|
||||
|
||||
Calling ``prepend`` will put the passed filter first in the list of
|
||||
transformations. For example, if you prepend a filter implementing
|
||||
encryption, and the pipe already had a filter that hex encoded the
|
||||
input, then the next message processed would be first encrypted,
|
||||
and *then* hex encoded.
|
||||
|
||||
.. cpp:function:: void Pipe::append(Filter* filter)
|
||||
|
||||
Like ``prepend``, but places the filter at the end of the message
|
||||
flow. This doesn't always do what you expect if there is a fork.
|
||||
|
||||
.. cpp:function:: void Pipe::pop()
|
||||
|
||||
Removes the first filter in the flow.
|
||||
|
||||
.. cpp:function:: void Pipe::reset()
|
||||
|
||||
Removes all the filters that the pipe currently holds - it is reset
|
||||
to an empty/no-op state. Any data that is being retained by the
|
||||
pipe is retained after a ``reset``, and ``reset`` does not affect
|
||||
message numbers (discussed later).
|
||||
|
||||
Giving Data to a Pipe
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Input to a ``Pipe`` is delimited into messages, which can be read from
|
||||
independently (ie, you can read 5 bytes from one message, and then all of
|
||||
another message, without either read affecting any other messages).
|
||||
|
||||
.. cpp:function:: void Pipe::start_msg()
|
||||
|
||||
Starts a new message; if a message was already running, an exception is
|
||||
thrown. After this function returns, you can call ``write``.
|
||||
|
||||
.. cpp:function:: void Pipe::write(const uint8_t* input, size_t length)
|
||||
|
||||
.. cpp:function:: void Pipe::write(const std::vector<uint8_t>& input)
|
||||
|
||||
.. cpp:function:: void Pipe::write(const std::string& input)
|
||||
|
||||
.. cpp:function:: void Pipe::write(DataSource& input)
|
||||
|
||||
.. cpp:function:: void Pipe::write(uint8_t input)
|
||||
|
||||
All versions of ``write`` write the input into the filter sequence.
|
||||
If a message is not currently active, an exception is thrown.
|
||||
|
||||
.. cpp:function:: void Pipe::end_msg()
|
||||
|
||||
End the currently active message
|
||||
|
||||
Sometimes, you may want to do only a single write per message. In this
|
||||
case, you can use the ``process_msg`` series of functions, which start
|
||||
a message, write their argument into the pipe, and then end the
|
||||
message. In this case you would not make any explicit calls to
|
||||
``start_msg``/``end_msg``.
|
||||
|
||||
Pipes can also be used with the ``>>`` operator, and will accept a
|
||||
``std::istream``, or on Unix systems with the ``fd_unix`` module, a
|
||||
Unix file descriptor. In either case, the entire contents of the file
|
||||
will be read into the pipe.
|
||||
|
||||
Getting Output from a Pipe
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieving the processed data from a pipe is a bit more complicated,
|
||||
for various reasons. The pipe will separate each message into a
|
||||
separate buffer, and you have to retrieve data from each message
|
||||
independently. Each of the reader functions has a final parameter that
|
||||
specifies what message to read from. If this parameter is set to
|
||||
``Pipe::DEFAULT_MESSAGE``, it will read the current default message
|
||||
(``DEFAULT_MESSAGE`` is also the default value of this parameter).
|
||||
|
||||
Functions in ``Pipe`` related to reading include:
|
||||
|
||||
.. cpp:function:: size_t Pipe::read(uint8_t* out, size_t len)
|
||||
|
||||
Reads up to ``len`` bytes into ``out``, and returns the number of
|
||||
bytes actually read.
|
||||
|
||||
.. cpp:function:: size_t Pipe::peek(uint8_t* out, size_t len)
|
||||
|
||||
Acts exactly like `read`, except the data is not actually read; the
|
||||
next read will return the same data.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> Pipe::read_all()
|
||||
|
||||
Reads the entire message into a buffer and returns it
|
||||
|
||||
.. cpp:function:: std::string Pipe::read_all_as_string()
|
||||
|
||||
Like ``read_all``, but it returns the data as a ``std::string``.
|
||||
No encoding is done; if the message contains raw binary, so will
|
||||
the string.
|
||||
|
||||
.. cpp:function:: size_t Pipe::remaining()
|
||||
|
||||
Returns how many bytes are left in the message
|
||||
|
||||
.. cpp:function:: Pipe::message_id Pipe::default_msg()
|
||||
|
||||
Returns the current default message number
|
||||
|
||||
.. cpp:function:: Pipe::message_id Pipe::message_count()
|
||||
|
||||
Returns the total number of messages currently in the pipe
|
||||
|
||||
.. cpp:function:: Pipe::set_default_msg(Pipe::message_id msgno)
|
||||
|
||||
Sets the default message number (which must be a valid message
|
||||
number for that pipe). The ability to set the default message number
|
||||
is particularly important in the case of using the file output
|
||||
operations (``<<`` with a ``std::ostream`` or Unix file descriptor),
|
||||
because there is no way to specify the message explicitly when using
|
||||
the output operator.
|
||||
|
||||
Pipe I/O for Unix File Descriptors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a minor feature, but it comes in handy sometimes. In all
|
||||
installations of the library, Botan's ``Pipe`` object overloads the
|
||||
``<<`` and ``>>`` operators for C++ iostream objects,
|
||||
which is usually more than sufficient for doing I/O.
|
||||
|
||||
However, there are cases where the iostream hierarchy does not map well to
|
||||
local 'file types', so there is also the ability to do I/O directly with Unix
|
||||
file descriptors. This is most useful when you want to read from or write to
|
||||
something like a TCP or Unix-domain socket, or a pipe, since for simple file
|
||||
access it's usually easier to just use C++'s file streams.
|
||||
|
||||
If ``BOTAN_EXT_PIPE_UNIXFD_IO`` is defined, then you can use the
|
||||
overloaded I/O operators with Unix file descriptors. For an example of this,
|
||||
check out the ``hash_fd`` example, included in the Botan distribution.
|
||||
|
||||
Filter Catalog
|
||||
---------------------------------
|
||||
|
||||
This section documents most of the useful filters included in the
|
||||
library.
|
||||
|
||||
Keyed Filters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A few sections ago, it was mentioned that ``Pipe`` can process
|
||||
multiple messages, treating each of them the same. Well, that was a
|
||||
bit of a lie. There are some algorithms (in particular, block ciphers
|
||||
not in ECB mode, and all stream ciphers) that change their state as
|
||||
data is put through them.
|
||||
|
||||
Naturally, you might well want to reset the keys or (in the case of
|
||||
block cipher modes) IVs used by such filters, so multiple messages can
|
||||
be processed using completely different keys, or new IVs, or new keys
|
||||
and IVs, or whatever. And in fact, even for a MAC or an ECB block
|
||||
cipher, you might well want to change the key used from message to
|
||||
message.
|
||||
|
||||
Enter ``Keyed_Filter``, which acts as an abstract interface for any
|
||||
filter that is uses keys: block cipher modes, stream ciphers, MACs,
|
||||
and so on. It has two functions, ``set_key`` and ``set_iv``. Calling
|
||||
``set_key`` will set (or reset) the key used by the algorithm. Setting
|
||||
the IV only makes sense in certain algorithms -- a call to ``set_iv``
|
||||
on an object that doesn't support IVs will cause an exception. You
|
||||
must call ``set_key`` *before* calling ``set_iv``.
|
||||
|
||||
Here's a example::
|
||||
|
||||
Keyed_Filter *aes, *hmac;
|
||||
Pipe pipe(new Base64_Decoder,
|
||||
// Note the assignments to the cast and hmac variables
|
||||
aes = get_cipher("AES-128/CBC", aes_key, iv),
|
||||
new Fork(
|
||||
0, // Read the section 'Fork' to understand this
|
||||
new Chain(
|
||||
hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12),
|
||||
new Base64_Encoder
|
||||
)
|
||||
)
|
||||
);
|
||||
pipe.start_msg();
|
||||
// use pipe for a while, decrypt some stuff, derive new keys and IVs
|
||||
pipe.end_msg();
|
||||
|
||||
aes->set_key(aes_key2);
|
||||
aes->set_iv(iv2);
|
||||
hmac->set_key(mac_key2);
|
||||
|
||||
pipe.start_msg();
|
||||
// use pipe for some other things
|
||||
pipe.end_msg();
|
||||
|
||||
There are some requirements to using ``Keyed_Filter`` that you must
|
||||
follow. If you call ``set_key`` or ``set_iv`` on a filter that is
|
||||
owned by a ``Pipe``, you must do so while the ``Pipe`` is
|
||||
"unlocked". This refers to the times when no messages are being
|
||||
processed by ``Pipe`` -- either before ``Pipe``'s ``start_msg`` is
|
||||
called, or after ``end_msg`` is called (and no new call to
|
||||
``start_msg`` has happened yet). Doing otherwise will result in
|
||||
undefined behavior, probably silently getting invalid output.
|
||||
|
||||
And remember: if you're resetting both values, reset the key *first*.
|
||||
|
||||
Cipher Filters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Getting a hold of a ``Filter`` implementing a cipher is very
|
||||
easy. Make sure you're including the header ``lookup.h``, and
|
||||
then call ``get_cipher``. You will pass the return value
|
||||
directly into a ``Pipe``. There are a couple different functions
|
||||
which do varying levels of initialization:
|
||||
|
||||
.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \
|
||||
SymmetricKey key, InitializationVector iv, Cipher_Dir dir)
|
||||
|
||||
.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \
|
||||
SymmetricKey key, Cipher_Dir dir)
|
||||
|
||||
The version that doesn't take an IV is useful for things that don't
|
||||
use them, like block ciphers in ECB mode, or most stream ciphers. If
|
||||
you specify a cipher spec that does want a IV, and you use the version
|
||||
that doesn't take one, an exception will be thrown. The ``dir``
|
||||
argument can be either ``Cipher_Dir::Encryption`` or ``Cipher_Dir::Decryption``.
|
||||
|
||||
The cipher_spec is a string that specifies what cipher is to be
|
||||
used. The general syntax for "cipher_spec" is "STREAM_CIPHER",
|
||||
"BLOCK_CIPHER/MODE", or "BLOCK_CIPHER/MODE/PADDING". In the case of
|
||||
stream ciphers, no mode is necessary, so just the name is
|
||||
sufficient. A block cipher requires a mode of some sort, which can be
|
||||
"ECB", "CBC", "CFB(n)", "OFB", "CTR-BE", or "EAX(n)". The argument to
|
||||
CFB mode is how many bits of feedback should be used. If you just use
|
||||
"CFB" with no argument, it will default to using a feedback equal to
|
||||
the block size of the cipher. EAX mode also takes an optional bit
|
||||
argument, which tells EAX how large a tag size to use~--~generally
|
||||
this is the size of the block size of the cipher, which is the default
|
||||
if you don't specify any argument.
|
||||
|
||||
In the case of the ECB and CBC modes, a padding method can also be
|
||||
specified. If it is not supplied, ECB defaults to not padding, and CBC
|
||||
defaults to using PKCS #5/#7 compatible padding. The padding methods
|
||||
currently available are "NoPadding", "PKCS7", "OneAndZeros", and
|
||||
"CTS". CTS padding is currently only available for CBC mode, but the
|
||||
others can also be used in ECB mode.
|
||||
|
||||
Some example "cipher_spec arguments are: "AES-128/CBC",
|
||||
"Blowfish/CTR-BE", "Serpent/XTS", and "AES-256/EAX".
|
||||
|
||||
"CTR-BE" refers to counter mode where the counter is incremented as if
|
||||
it were a big-endian encoded integer. This is compatible with most
|
||||
other implementations, but it is possible some will use the
|
||||
incompatible little endian convention. This version would be denoted
|
||||
as "CTR-LE" if it were supported.
|
||||
|
||||
"EAX" is a new cipher mode designed by Wagner, Rogaway, and
|
||||
Bellare. It is an authenticated cipher mode (that is, no separate
|
||||
authentication is needed), has provable security, and is free from
|
||||
patent entanglements. It runs about half as fast as most of the other
|
||||
cipher modes (like CBC, OFB, or CTR), which is not bad considering you
|
||||
don't need to use an authentication code.
|
||||
|
||||
Hashes and MACs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Hash functions and MACs don't need anything special when it comes to
|
||||
filters. Both just take their input and produce no output until
|
||||
``end_msg`` is called, at which time they complete the hash or MAC and
|
||||
send that as output.
|
||||
|
||||
These filters take a string naming the type to be used. If for some
|
||||
reason you name something that doesn't exist, an exception will be thrown.
|
||||
|
||||
.. cpp:function:: Hash_Filter::Hash_Filter(std::string hash, size_t outlen = 0)
|
||||
|
||||
This constructor creates a filter that hashes its input with
|
||||
``hash``. When ``end_msg`` is called on the owning pipe, the hash is
|
||||
completed and the digest is sent on to the next filter in the
|
||||
pipeline. The parameter ``outlen`` specifies how many bytes of the
|
||||
hash output will be passed along to the next filter when ``end_msg``
|
||||
is called. By default, it will pass the entire hash.
|
||||
|
||||
Examples of names for ``Hash_Filter`` are "SHA-1" and "Whirlpool".
|
||||
|
||||
.. cpp:function:: MAC_Filter::MAC_Filter(std::string mac, SymmetricKey key, size_t outlen = 0)
|
||||
|
||||
This constructor takes a name for a mac, such as "HMAC(SHA-1)" or
|
||||
"CMAC(AES-128)", along with a key to use. The optional ``outlen``
|
||||
works the same as in ``Hash_Filter``.
|
||||
|
||||
Encoders
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Often you want your data to be in some form of text (for sending over
|
||||
channels that aren't 8-bit clean, printing it, etc). The filters
|
||||
``Hex_Encoder`` and ``Base64_Encoder`` will convert arbitrary binary
|
||||
data into hex or base64 formats. Not surprisingly, you can use
|
||||
``Hex_Decoder`` and ``Base64_Decoder`` to convert it back into its
|
||||
original form.
|
||||
|
||||
Both of the encoders can take a few options about how the data should
|
||||
be formatted (all of which have defaults). The first is a ``bool``
|
||||
which says if the encoder should insert line breaks. This defaults to
|
||||
false. Line breaks don't matter either way to the decoder, but it
|
||||
makes the output a bit more appealing to the human eye, and a few
|
||||
transport mechanisms (notably some email systems) limit the maximum
|
||||
line length.
|
||||
|
||||
The second encoder option is an integer specifying how long such lines
|
||||
will be (obviously this will be ignored if line-breaking isn't being
|
||||
used). The default tends to be in the range of 60-80 characters, but
|
||||
is not specified. If you want a specific value, set it. Otherwise the
|
||||
default should be fine.
|
||||
|
||||
Lastly, ``Hex_Encoder`` takes an argument of type ``Case``, which can
|
||||
be ``Uppercase`` or ``Lowercase`` (default is ``Uppercase``). This
|
||||
specifies what case the characters A-F should be output as. The base64
|
||||
encoder has no such option, because it uses both upper and lower case
|
||||
letters for its output.
|
||||
|
||||
You can find the declarations for these types in ``hex_filt.h`` and
|
||||
``b64_filt.h``.
|
||||
|
||||
Writing New Filters
|
||||
---------------------------------
|
||||
|
||||
The system of filters and pipes was designed in an attempt to make it
|
||||
as simple as possible to write new filter types. There are four
|
||||
functions that need to be implemented by a class deriving from
|
||||
``Filter``:
|
||||
|
||||
.. cpp:function:: std::string Filter::name() const
|
||||
|
||||
This should just return a useful decription of the filter object.
|
||||
|
||||
.. cpp:function:: void Filter::write(const uint8_t* input, size_t length)
|
||||
|
||||
This function is what is called when a filter receives input for it
|
||||
to process. The filter is not required to process the data right
|
||||
away; many filters buffer their input before producing any output. A
|
||||
filter will usually have ``write`` called many times during its
|
||||
lifetime.
|
||||
|
||||
.. cpp:function:: void Filter::send(uint8_t* output, size_t length)
|
||||
|
||||
Eventually, a filter will want to produce some output to send along
|
||||
to the next filter in the pipeline. It does so by calling ``send``
|
||||
with whatever it wants to send along to the next filter. There is
|
||||
also a version of ``send`` taking a single byte argument, as a
|
||||
convenience.
|
||||
|
||||
.. note::
|
||||
|
||||
Normally a filter does not need to override ``send``, though it
|
||||
can for special handling. It does however need to call this
|
||||
function whenever it wants to produce output.
|
||||
|
||||
.. cpp:function:: void Filter::start_msg()
|
||||
|
||||
Implementing this function is optional. Implement it if your filter
|
||||
would like to do some processing or setup at the start of each
|
||||
message, such as allocating a data structure.
|
||||
|
||||
.. cpp:function:: void Filter::end_msg()
|
||||
|
||||
Implementing this function is optional. It is called when it has
|
||||
been requested that filters finish up their computations. The filter
|
||||
should finish up with whatever computation it is working on (for
|
||||
example, a compressing filter would flush the compressor and
|
||||
``send`` the final block), and empty any buffers in preparation for
|
||||
processing a fresh new set of input.
|
||||
|
||||
Additionally, if necessary, filters can define a constructor that
|
||||
takes any needed arguments, and a destructor to deal with deallocating
|
||||
memory, closing files, etc.
|
||||
|
@ -1,60 +0,0 @@
|
||||
========================================
|
||||
Footguns
|
||||
========================================
|
||||
|
||||
This section notes areas where certain usages can cause confusing bugs or problems.
|
||||
|
||||
Static Objects
|
||||
------------------
|
||||
|
||||
If you maintain ``static`` variables which hold Botan objects, you will perhaps
|
||||
find that in some circumstances your application crashes in strange ways on
|
||||
shutdown. That is because, at least on some operating systems, Botan uses a
|
||||
locked memory pool as backing storage for the ``secure_vector`` type. This pool
|
||||
allocates out of pages which have been locked into memory using ``mlock`` or
|
||||
``VirtualLock`` system calls.
|
||||
|
||||
If your variable happens to be destroyed before the pool, all is well. If the
|
||||
pool happens to be destroyed before the variable, then when the object goes to
|
||||
free its memory, a crash will occur.
|
||||
|
||||
This is basically the famous C++ "Static Initialization Order Fiasco", except
|
||||
in reverse.
|
||||
|
||||
The best course of action is to avoid ``static`` variables. If that is
|
||||
impossible or inconvenient, one option is to disable the pool, either at build
|
||||
time (disable the ``locking_allocator`` module) or at runtime. Unfortunately the
|
||||
runtime setting requires setting an environment variable (see :ref:`env_vars`),
|
||||
and doing so consistently *prior to static intialization* is not trivial, due to
|
||||
the previously mentioned fiasco. One option might be to use GCC's
|
||||
``constructor`` function attribute.
|
||||
|
||||
Another approach is to use the utility class ``Allocator_Initializer`` (declared
|
||||
in ``mem_ops.h``) as an associated ``static`` variable in your code. As long as
|
||||
the ``Allocator_Initializer`` is created *before* your static variables, that
|
||||
means the allocator is created before your object, and thus will be destroyed
|
||||
after your object is destroyed.
|
||||
|
||||
Ideally a more satisfactory solution to this issue could be found, especially
|
||||
given the difficulty of disabling the pool at runtime.
|
||||
|
||||
Multithreaded Access
|
||||
----------------------
|
||||
|
||||
It is perfectly safe to use the library from multiple threads.
|
||||
|
||||
It is *not* safe to use the same object from multiple threads, without some form
|
||||
of external serialization or locking.
|
||||
|
||||
There are a few exceptions to this rule, where the type itself maintains an
|
||||
internal mutexes. This will be noted in the respective documentation for that type.
|
||||
|
||||
Use of `fork`
|
||||
----------------------
|
||||
|
||||
If you use the `fork` syscall in your code, and attempt to use the library in
|
||||
both processes, likely bad things will happen due to internal locks. You can
|
||||
avoid this problem by either at build time disabling the features associated
|
||||
with these locks (namely ``locking_allocator`` and ``thread_utils``) or
|
||||
disabling them at runtime using :ref:`env_vars`, ideally at the very start of
|
||||
`main`.
|
@ -1,98 +0,0 @@
|
||||
Format Preserving Encryption
|
||||
========================================
|
||||
|
||||
Format preserving encryption (FPE) refers to a set of techniques for
|
||||
encrypting data such that the ciphertext has the same format as the
|
||||
plaintext. For instance, you can use FPE to encrypt credit card
|
||||
numbers with valid checksums such that the ciphertext is also an
|
||||
credit card number with a valid checksum, or similarly for bank
|
||||
account numbers, US Social Security numbers, or even more general
|
||||
mappings like English words onto other English words.
|
||||
|
||||
The scheme currently implemented in botan is called FE1, and described
|
||||
in the paper `Format Preserving Encryption
|
||||
<https://eprint.iacr.org/2009/251>`_ by Mihir Bellare, Thomas
|
||||
Ristenpart, Phillip Rogaway, and Till Stegers. FPE is an area of
|
||||
ongoing standardization and it is likely that other schemes will be
|
||||
included in the future.
|
||||
|
||||
To encrypt an arbitrary value using FE1, you need to use a ranking
|
||||
method. Basically, the idea is to assign an integer to every value you
|
||||
might encrypt. For instance, a 16 digit credit card number consists of
|
||||
a 15 digit code plus a 1 digit checksum. So to encrypt a credit card
|
||||
number, you first remove the checksum, encrypt the 15 digit value
|
||||
modulo 10\ :sup:`15`, and then calculate what the checksum is for the
|
||||
new (ciphertext) number. Or, if you were encrypting words in a
|
||||
dictionary, you could rank the words by their lexicographical order,
|
||||
and choose the modulus to be the number of words in the dictionary.
|
||||
|
||||
The interfaces for FE1 are defined in the header ``fpe_fe1.h``:
|
||||
|
||||
.. versionadded:: 2.5.0
|
||||
|
||||
.. cpp:class:: FPE_FE1
|
||||
|
||||
.. cpp:function:: FPE_FE1(const BigInt& n, size_t rounds = 5, \
|
||||
bool compat_mode = false, \
|
||||
std::string mac_algo = "HMAC(SHA-256)")
|
||||
|
||||
Initialize an FPE operation to encrypt/decrypt integers less
|
||||
than *n*. It is expected that *n* is trivially factorable into
|
||||
small integers. Common usage would be n to be a power of 10.
|
||||
|
||||
Note that the default parameters to this constructor are
|
||||
**incompatible** with the ``fe1_encrypt`` and ``fe1_decrypt``
|
||||
function originally added in 1.9.17. For compatibility, use
|
||||
3 rounds and set ``compat_mode`` to true.
|
||||
|
||||
.. cpp:function:: BigInt encrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const
|
||||
|
||||
Encrypts the value *x* modulo the value *n* using the *key* and *tweak*
|
||||
specified. Returns an integer less than *n*. The *tweak* is a value that
|
||||
does not need to be secret that parameterizes the encryption function. For
|
||||
instance, if you were encrypting a database column with a single key, you
|
||||
could use a per-row-unique integer index value as the tweak. The same
|
||||
tweak value must be used during decryption.
|
||||
|
||||
.. cpp:function:: BigInt decrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const
|
||||
|
||||
Decrypts an FE1 ciphertext. The *tweak* must be the same as that provided
|
||||
to the encryption function. Returns the plaintext integer.
|
||||
|
||||
Note that there is not any implicit authentication or checking of data in
|
||||
FE1, so if you provide an incorrect key or tweak the result is simply a
|
||||
random integer.
|
||||
|
||||
.. cpp:function:: BigInt encrypt(const BigInt& x, uint64_t tweak)
|
||||
|
||||
Convenience version of encrypt taking an integer tweak.
|
||||
|
||||
.. cpp:function:: BigInt decrypt(const BigInt& x, uint64_t tweak)
|
||||
|
||||
Convenience version of decrypt taking an integer tweak.
|
||||
|
||||
There are two functions that handle the entire FE1 encrypt/decrypt operation.
|
||||
These are the original interface to FE1, first added in 1.9.17. However because
|
||||
they do the entire setup cost for each operation, they are significantly slower
|
||||
than the class-based API presented above.
|
||||
|
||||
.. warning:: These functions are hardcoded to use 3 rounds, which may be
|
||||
insufficient depending on the chosen modulus.
|
||||
|
||||
.. cpp:function:: BigInt FPE::fe1_encrypt(const BigInt& n, const BigInt& X, \
|
||||
const SymmetricKey& key, const std::vector<uint8_t>& tweak)
|
||||
|
||||
This creates an FPE_FE1 object, sets the key, and encrypts *X* using
|
||||
the provided tweak.
|
||||
|
||||
.. cpp:function:: BigInt FPE::fe1_decrypt(const BigInt& n, const BigInt& X, \
|
||||
const SymmetricKey& key, const std::vector<uint8_t>& tweak)
|
||||
|
||||
This creates an FPE_FE1 object, sets the key, and decrypts *X* using
|
||||
the provided tweak.
|
||||
|
||||
This example encrypts a credit card number with a valid `Luhn checksum
|
||||
<https://en.wikipedia.org/wiki/Luhn_algorithm>`_ to another number with the same
|
||||
format, including a correct checksum.
|
||||
|
||||
.. literalinclude:: ../../src/cli/cc_enc.cpp
|
@ -1,312 +0,0 @@
|
||||
Hash Functions and Checksums
|
||||
=============================
|
||||
|
||||
Hash functions are one-way functions, which map data of arbitrary size to a
|
||||
fixed output length. Most of the hash functions in Botan are designed to be
|
||||
cryptographically secure, which means that it is computationally infeasible to
|
||||
create a collision (finding two inputs with the same hash) or preimages (given a
|
||||
hash output, generating an arbitrary input with the same hash). But note that
|
||||
not all such hash functions meet their goals, in particular MD4 and MD5 are
|
||||
trivially broken. However they are still included due to their wide adoption in
|
||||
various protocols.
|
||||
|
||||
The class :cpp:class:`HashFunction` is defined in `botan/hash.h`.
|
||||
|
||||
Using a hash function is typically split into three stages: initialization,
|
||||
update, and finalization (often referred to as a IUF interface). The
|
||||
initialization stage is implicit: after creating a hash function object, it is
|
||||
ready to process data. Then update is called one or more times. Calling update
|
||||
several times is equivalent to calling it once with all of the arguments
|
||||
concatenated. After completing a hash computation (eg using ``final``), the
|
||||
internal state is reset to begin hashing a new message.
|
||||
|
||||
.. cpp:class:: HashFunction
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<HashFunction> create(const std::string& name)
|
||||
|
||||
Return a newly allocated hash function object, or nullptr if the
|
||||
name is not recognized.
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<HashFunction> create_or_throw(const std::string& name)
|
||||
|
||||
Like ``create`` except that it will throw an exception instead of
|
||||
returning nullptr.
|
||||
|
||||
.. cpp:function:: size_t output_length()
|
||||
|
||||
Return the size (in *bytes*) of the output of this function.
|
||||
|
||||
.. cpp:function:: void update(const uint8_t* input, size_t length)
|
||||
|
||||
Updates the computation with *input*.
|
||||
|
||||
.. cpp:function:: void update(uint8_t input)
|
||||
|
||||
Updates the computation with *input*.
|
||||
|
||||
.. cpp:function:: void update(const std::vector<uint8_t>& input)
|
||||
|
||||
Updates the computation with *input*.
|
||||
|
||||
.. cpp:function:: void update(const std::string& input)
|
||||
|
||||
Updates the computation with *input*.
|
||||
|
||||
.. cpp:function:: void final(uint8_t* out)
|
||||
|
||||
Finalize the calculation and place the result into ``out``.
|
||||
For the argument taking an array, exactly ``output_length`` bytes will
|
||||
be written. After you call ``final``, the algorithm is reset to
|
||||
its initial state, so it may be reused immediately.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> final()
|
||||
|
||||
Similar to the other function of the same name, except it returns
|
||||
the result in a newly allocated vector.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> process(const uint8_t in[], size_t length)
|
||||
|
||||
Equivalent to calling ``update`` followed by ``final``.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> process(const std::string& in)
|
||||
|
||||
Equivalent to calling ``update`` followed by ``final``.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<HashFunction> new_object()
|
||||
|
||||
Return a newly allocated HashFunction object of the same type as this one.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<HashFunction> copy_state()
|
||||
|
||||
Return a newly allocated HashFunction object of the same type as this one,
|
||||
whose internal state matches the current state of this.
|
||||
|
||||
Code Example
|
||||
------------
|
||||
|
||||
Assume we want to calculate the SHA-256, SHA-384, and SHA-3 hash digests of the STDIN stream using the Botan library.
|
||||
|
||||
.. literalinclude:: /../src/examples/hash.cpp
|
||||
:language: cpp
|
||||
|
||||
Available Hash Functions
|
||||
------------------------------
|
||||
|
||||
The following cryptographic hash functions are implemented. If in doubt,
|
||||
any of SHA-384, SHA-3, or BLAKE2b are fine choices.
|
||||
|
||||
BLAKE2b
|
||||
^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_BLAKE2B`` is defined.
|
||||
|
||||
A recently designed hash function. Very fast on 64-bit processors. Can output a
|
||||
hash of any length between 1 and 64 bytes, this is specified by passing a value
|
||||
to the constructor with the desired length.
|
||||
|
||||
Named like "Blake2b" which selects default 512-bit output, or as
|
||||
"Blake2b(256)" to select 256 bits of output.
|
||||
|
||||
GOST-34.11
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 2.11
|
||||
|
||||
Available if ``BOTAN_HAS_GOST_34_11`` is defined.
|
||||
|
||||
Russian national standard hash. It is old, slow, and has some weaknesses. Avoid
|
||||
it unless you must.
|
||||
|
||||
.. warning::
|
||||
As this hash function is no longer approved by the latest Russian standards,
|
||||
support for GOST 34.11 hash is deprecated and will be removed in a future
|
||||
major release.
|
||||
|
||||
Keccak-1600
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_KECCAK`` is defined.
|
||||
|
||||
An older (and incompatible) variant of SHA-3, but sometimes used. Prefer SHA-3 in
|
||||
new code.
|
||||
|
||||
MD4
|
||||
^^^^^^^^^
|
||||
|
||||
An old and now broken hash function. Available if ``BOTAN_HAS_MD4`` is defined.
|
||||
|
||||
.. warning::
|
||||
MD4 collisions can be easily created. There is no safe cryptographic use
|
||||
for this function.
|
||||
|
||||
.. warning::
|
||||
Support for MD4 is deprecated and will be removed in a future major release.
|
||||
|
||||
MD5
|
||||
^^^^^^^^^
|
||||
|
||||
An old and now broken hash function. Available if ``BOTAN_HAS_MD5`` is defined.
|
||||
|
||||
.. warning::
|
||||
MD5 collisions can be easily created. MD5 should never be used for signatures.
|
||||
|
||||
RIPEMD-160
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_RIPEMD160`` is defined.
|
||||
|
||||
A 160 bit hash function, quite old but still thought to be secure (up to the
|
||||
limit of 2**80 computation required for a collision which is possible with any
|
||||
160 bit hash function). Somewhat deprecated these days. Prefer SHA-2 or SHA-3
|
||||
in new code.
|
||||
|
||||
SHA-1
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SHA1`` is defined.
|
||||
|
||||
Widely adopted NSA designed hash function. Use SHA-2 or SHA-3 in new code.
|
||||
|
||||
.. warning::
|
||||
|
||||
SHA-1 collisions can now be created by moderately resourced attackers. It
|
||||
must never be used for signatures.
|
||||
|
||||
SHA-256
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SHA2_32`` is defined.
|
||||
|
||||
Relatively fast 256 bit hash function, thought to be secure.
|
||||
|
||||
Also includes the variant SHA-224. There is no real reason to use SHA-224.
|
||||
|
||||
SHA-512
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SHA2_64`` is defined.
|
||||
|
||||
SHA-512 is faster than SHA-256 on 64-bit processors. Also includes the
|
||||
truncated variants SHA-384 and SHA-512/256, which have the advantage
|
||||
of avoiding message extension attacks.
|
||||
|
||||
SHA-3
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SHA3`` is defined.
|
||||
|
||||
The new NIST standard hash. Fairly slow.
|
||||
|
||||
Supports 224, 256, 384 or 512 bit outputs. SHA-3 is faster with
|
||||
smaller outputs. Use as "SHA-3(256)" or "SHA-3(512)". Plain "SHA-3"
|
||||
selects default 512 bit output.
|
||||
|
||||
SHAKE (SHAKE-128, SHAKE-256)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SHAKE`` is defined.
|
||||
|
||||
These are actually XOFs (extensible output functions) based on SHA-3, which can
|
||||
output a value of any byte length. For example "SHAKE-128(1024)" will produce
|
||||
1024 bits of output. The specified length must be a multiple of 8.
|
||||
|
||||
SM3
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SM3`` is defined.
|
||||
|
||||
Chinese national hash function, 256 bit output. Widely used in industry there.
|
||||
Fast and seemingly secure, but no reason to prefer it over SHA-2 or SHA-3 unless
|
||||
required.
|
||||
|
||||
Skein-512
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_SKEIN_512`` is defined.
|
||||
|
||||
A contender for the NIST SHA-3 competition. Very fast on 64-bit systems. Can
|
||||
output a hash of any length between 1 and 64 bytes. It also accepts an optional
|
||||
"personalization string" which can create variants of the hash. This is useful
|
||||
for domain separation.
|
||||
|
||||
To set a personalization string set the second param to any value,
|
||||
typically ASCII strings are used. Examples "Skein-512(256)" or
|
||||
"Skein-512(384,personalization_string)".
|
||||
|
||||
Streebog (Streebog-256, Streebog-512)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_STREEBOG`` is defined.
|
||||
|
||||
Newly designed Russian national hash function. Due to use of input-dependent
|
||||
table lookups, it is vulnerable to side channels. There is no reason to use it
|
||||
unless compatibility is needed.
|
||||
|
||||
.. warning::
|
||||
The Streebog Sbox has recently been revealed to have a hidden structure which
|
||||
interacts with its linear layer in a way which may provide a backdoor when
|
||||
used in certain ways. Avoid Streebog if at all possible.
|
||||
|
||||
Whirlpool
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_WHIRLPOOL`` is defined.
|
||||
|
||||
A 512-bit hash function standardized by ISO and NESSIE. Relatively slow, and due
|
||||
to the table based implementation it is potentially vulnerable to cache based
|
||||
side channels.
|
||||
|
||||
Hash Function Combiners
|
||||
---------------------------
|
||||
|
||||
These are functions which combine multiple hash functions to create a new hash
|
||||
function. They are typically only used in specialized applications.
|
||||
|
||||
Parallel
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_PARALLEL_HASH`` is defined.
|
||||
|
||||
Parallel simply concatenates multiple hash functions. For example
|
||||
"Parallel(SHA-256,SHA-512)" outputs a 256+512 bit hash created by hashing the
|
||||
input with both SHA-256 and SHA-512 and concatenating the outputs.
|
||||
|
||||
Note that due to the "multicollision attack" it turns out that generating a
|
||||
collision for multiple parallel hash functions is no harder than generating a
|
||||
collision for the strongest hash function.
|
||||
|
||||
Comp4P
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_COMB4P`` is defined.
|
||||
|
||||
This combines two cryptographic hashes in such a way that preimage and collision
|
||||
attacks are provably at least as hard as a preimage or collision attack on the
|
||||
strongest hash.
|
||||
|
||||
Checksums
|
||||
----------------
|
||||
|
||||
.. note:: Checksums are not suitable for cryptographic use, but can be used for
|
||||
error checking purposes.
|
||||
|
||||
Adler32
|
||||
^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_ADLER32`` is defined.
|
||||
|
||||
The Adler32 checksum is used in the zlib format. 32 bit output.
|
||||
|
||||
CRC24
|
||||
^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_CRC24`` is defined.
|
||||
|
||||
This is the CRC function used in OpenPGP. 24 bit output.
|
||||
|
||||
CRC32
|
||||
^^^^^^^^^^^
|
||||
|
||||
Available if ``BOTAN_HAS_CRC32`` is defined.
|
||||
|
||||
This is the 32-bit CRC used in protocols such as Ethernet, gzip, PNG, etc.
|
@ -1,153 +0,0 @@
|
||||
|
||||
.. _key_derivation_function:
|
||||
|
||||
Key Derivation Functions (KDF)
|
||||
========================================
|
||||
|
||||
Key derivation functions are used to turn some amount of shared secret material
|
||||
into uniform random keys suitable for use with symmetric algorithms. An example
|
||||
of an input which is useful for a KDF is a shared secret created using
|
||||
Diffie-Hellman key agreement.
|
||||
|
||||
Typically a KDF is also used with a *salt* and a *label*. The *salt* should be
|
||||
some random information which is available to all of the parties that would need
|
||||
to use the KDF; this could be performed by setting the salt to some kind of
|
||||
session identifier, or by having one of the parties generate a random salt and
|
||||
including it in a message.
|
||||
|
||||
The *label* is used to bind the KDF output to some specific context. For
|
||||
instance if you were using the KDF to derive a specific key referred to as the
|
||||
"message key" in the protocol description, you might use a label of "FooProtocol
|
||||
v2 MessageKey". This labeling ensures that if you accidentally use the same
|
||||
input key and salt in some other context, you still use different keys in the
|
||||
two contexts.
|
||||
|
||||
.. cpp:class:: KDF
|
||||
|
||||
.. cpp:function:: std::unique_ptr<KDF> KDF::create(const std::string& algo)
|
||||
|
||||
Create a new KDF object. Returns nullptr if the named key derivation
|
||||
function was not available
|
||||
|
||||
.. cpp:function:: std::unique_ptr<KDF> KDF::create_or_throw(const std::string& algo)
|
||||
|
||||
Create a new KDF object. Throws an exception if the named key derivation
|
||||
function was not available
|
||||
|
||||
.. cpp:function:: template<concepts::resizable_byte_buffer T = secure_vector<uint8_t>> \
|
||||
T derive_key(size_t key_len, \
|
||||
std::span<const uint8_t> secret, \
|
||||
std::span<const uint8_t> salt, \
|
||||
std::span<const uint8_t> label) const
|
||||
|
||||
This version is parameterized to the output buffer type, so it can be used
|
||||
to return a ``std::vector``, a ``secure_vector``, or anything else
|
||||
satisfying the ``resizable_byte_buffer`` concept.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> derive_key( \
|
||||
const uint8_t secret[], \
|
||||
size_t secret_len, \
|
||||
const uint8_t salt[], \
|
||||
size_t salt_len, \
|
||||
const uint8_t label[], \
|
||||
size_t label_len) const
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> derive_key( \
|
||||
size_t key_len, const std::vector<uint8_t>& secret, \
|
||||
const std::vector<uint8_t>& salt, \
|
||||
const std::vector<uint8_t>& label) const
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> derive_key( \
|
||||
size_t key_len, const std::vector<uint8_t>& secret, \
|
||||
const uint8_t* salt, size_t salt_len) const
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> derive_key( \
|
||||
size_t key_len, const uint8_t* secret, size_t secret_len, \
|
||||
const std::string& salt) const
|
||||
|
||||
All variations on the same theme. Deterministically creates a
|
||||
uniform random value from *secret*, *salt*, and *label*, whose
|
||||
meaning is described above.
|
||||
|
||||
Code Example
|
||||
------------
|
||||
|
||||
An example demonstrating using the API to hash a secret using HKDF
|
||||
|
||||
.. literalinclude:: /../src/examples/kdf.cpp
|
||||
:language: cpp
|
||||
|
||||
|
||||
Available KDFs
|
||||
-------------------
|
||||
|
||||
Botan includes many different KDFs simply because different protocols and.
|
||||
standards have created subtly different approaches to this problem. For new
|
||||
code, use HKDF which is conservative, well studied, widely implemented and NIST
|
||||
approved. There is no technical reason (besides compatability) to choose any
|
||||
other KDF.
|
||||
|
||||
HKDF
|
||||
~~~~~
|
||||
|
||||
Defined in RFC 5869, HKDF uses HMAC to process inputs. Also available
|
||||
are variants HKDF-Extract and HKDF-Expand. HKDF is the combined
|
||||
Extract+Expand operation. Use the combined HKDF unless you need
|
||||
compatibility with some other system.
|
||||
|
||||
Available if ``BOTAN_HAS_HKDF`` is defined.
|
||||
|
||||
KDF2
|
||||
~~~~~
|
||||
|
||||
KDF2 comes from IEEE 1363. It uses a hash function.
|
||||
|
||||
Available if ``BOTAN_HAS_KDF2`` is defined.
|
||||
|
||||
KDF1-18033
|
||||
~~~~~~~~~~~~
|
||||
|
||||
KDF1 from ISO 18033-2. Very similar to (but incompatible with) KDF2.
|
||||
|
||||
Available if ``BOTAN_HAS_KDF1_18033`` is defined.
|
||||
|
||||
KDF1
|
||||
~~~~~~
|
||||
|
||||
KDF1 from IEEE 1363. It can only produce an output at most the length
|
||||
of the hash function used.
|
||||
|
||||
Available if ``BOTAN_HAS_KDF1`` is defined.
|
||||
|
||||
X9.42 PRF
|
||||
~~~~~~~~~~
|
||||
|
||||
A KDF from ANSI X9.42. Sometimes used for Diffie-Hellman. However it is
|
||||
overly complicated and is fixed to use only SHA-1.
|
||||
|
||||
Available if ``BOTAN_HAS_X942_PRF`` is defined.
|
||||
|
||||
.. warning::
|
||||
X9.42 PRF is deprecated and will be removed in a future major release.
|
||||
|
||||
SP800-108
|
||||
~~~~~~~~~~
|
||||
|
||||
KDFs from NIST SP 800-108. Variants include "SP800-108-Counter",
|
||||
"SP800-108-Feedback" and "SP800-108-Pipeline".
|
||||
|
||||
Available if ``BOTAN_HAS_SP800_108`` is defined.
|
||||
|
||||
SP800-56A
|
||||
~~~~~~~~~~
|
||||
|
||||
KDF from NIST SP 800-56A.
|
||||
|
||||
Available if ``BOTAN_HAS_SP800_56A`` is defined.
|
||||
|
||||
SP800-56C
|
||||
~~~~~~~~~~
|
||||
|
||||
KDF from NIST SP 800-56C.
|
||||
|
||||
Available if ``BOTAN_HAS_SP800_56C`` is defined.
|
@ -1,60 +0,0 @@
|
||||
AES Key Wrapping
|
||||
=================================
|
||||
|
||||
NIST specifies two mechanisms for wrapping (encrypting) symmetric keys using
|
||||
another key. The first (and older, more widely supported) method requires the
|
||||
input be a multiple of 8 bytes long. The other allows any length input, though
|
||||
only up to 2**32 bytes.
|
||||
|
||||
These algorithms are described in NIST SP 800-38F, and RFCs 3394 and 5649.
|
||||
|
||||
This API, defined in ``nist_keywrap.h``, first became available in version 2.4.0
|
||||
|
||||
These functions take an arbitrary 128-bit block cipher object, which must
|
||||
already have been keyed with the key encryption key. NIST only allows these
|
||||
functions with AES, but any 128-bit cipher will do and some other implementations
|
||||
(such as in OpenSSL) do also allow other ciphers. Use AES for best interop.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> nist_key_wrap(const uint8_t input[], \
|
||||
size_t input_len, const BlockCipher& bc)
|
||||
|
||||
This performs KW (key wrap) mode. The input must be a multiple of 8 bytes long.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> nist_key_unwrap(const uint8_t input[], \
|
||||
size_t input_len, const BlockCipher& bc)
|
||||
|
||||
This unwraps the result of nist_key_wrap, or throw Invalid_Authentication_Tag on error.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> nist_key_wrap_padded(const uint8_t input[], \
|
||||
size_t input_len, const BlockCipher& bc)
|
||||
|
||||
This performs KWP (key wrap with padding) mode. The input can be any length.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> nist_key_unwrap_padded(const uint8_t input[], \
|
||||
size_t input_len, const BlockCipher& bc)
|
||||
|
||||
This unwraps the result of nist_key_wrap_padded, or throws Invalid_Authentication_Tag
|
||||
on error.
|
||||
|
||||
RFC 3394 Interface
|
||||
-----------------------------
|
||||
|
||||
This is an older interface that was first available (with slight changes) in
|
||||
1.10, and available in its current form since 2.0 release. It uses a 128-bit,
|
||||
192-bit, or 256-bit key to encrypt an input key. AES is always used. The input
|
||||
must be a multiple of 8 bytes; if not an exception is thrown.
|
||||
|
||||
This interface is defined in ``rfc3394.h``.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key, \
|
||||
const SymmetricKey& kek)
|
||||
|
||||
Wrap the input key using kek (the key encryption key), and return the result. It will
|
||||
be 8 bytes longer than the input key.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key, \
|
||||
const SymmetricKey& kek)
|
||||
|
||||
Unwrap a key wrapped with rfc3394_keywrap.
|
||||
|
||||
|
@ -1,195 +0,0 @@
|
||||
|
||||
.. _mac:
|
||||
|
||||
Message Authentication Codes (MAC)
|
||||
===================================
|
||||
|
||||
A Message Authentication Code algorithm computes a tag over a message utilizing
|
||||
a shared secret key. Thus a valid tag confirms the authenticity and integrity of
|
||||
the message. Only entities in possession of the shared secret key are able to
|
||||
verify the tag.
|
||||
|
||||
.. note::
|
||||
|
||||
When combining a MAC with unauthenticated encryption mode, prefer to first
|
||||
encrypt the message and then MAC the ciphertext. The alternative is to MAC
|
||||
the plaintext, which depending on exact usage can suffer serious security
|
||||
issues. For a detailed discussion of this issue see the paper "The Order of
|
||||
Encryption and Authentication for Protecting Communications" by Hugo
|
||||
Krawczyk
|
||||
|
||||
The Botan MAC computation is split into five stages.
|
||||
|
||||
#. Instantiate the MAC algorithm.
|
||||
#. Set the secret key.
|
||||
#. Process IV.
|
||||
#. Process data.
|
||||
#. Finalize the MAC computation.
|
||||
|
||||
.. cpp:class:: MessageAuthenticationCode
|
||||
|
||||
.. cpp:function:: std::string name() const
|
||||
|
||||
Returns a human-readable string of the name of this algorithm.
|
||||
|
||||
.. cpp:function:: void clear()
|
||||
|
||||
Clear the key.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<MessageAuthenticationCode> new_object() const
|
||||
|
||||
Return a newly allocated object of the same type as this one.
|
||||
The new object is unkeyed.
|
||||
|
||||
.. cpp:function:: void set_key(const uint8_t* key, size_t length)
|
||||
|
||||
Set the shared MAC key for the calculation. This function has to be called before the data is processed.
|
||||
|
||||
.. cpp:function:: bool valid_keylength(size_t length) const
|
||||
|
||||
This function returns true if and only if *length* is a valid
|
||||
keylength for the algorithm.
|
||||
|
||||
.. cpp:function:: size_t minimum_keylength() const
|
||||
|
||||
Return the smallest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: size_t maximum_keylength() const
|
||||
|
||||
Return the largest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: void start(const uint8_t* nonce, size_t nonce_len)
|
||||
|
||||
Set the IV for the MAC calculation. Note that not all MAC algorithms require an IV.
|
||||
If an IV is required, the function has to be called before the data is processed.
|
||||
For algorithms that don't require it, the call can be omitted, or else called
|
||||
with ``nonce_len`` of zero.
|
||||
|
||||
.. cpp:function:: void update(const uint8_t* input, size_t length)
|
||||
|
||||
Process the passed data.
|
||||
|
||||
.. cpp:function:: void update(const secure_vector<uint8_t>& in)
|
||||
|
||||
Process the passed data.
|
||||
|
||||
.. cpp:function:: void update(uint8_t in)
|
||||
|
||||
Process a single byte.
|
||||
|
||||
.. cpp:function:: void final(uint8_t* out)
|
||||
|
||||
Complete the MAC computation and write the calculated tag to the passed byte array.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> final()
|
||||
|
||||
Complete the MAC computation and return the calculated tag.
|
||||
|
||||
.. cpp:function:: bool verify_mac(const uint8_t* mac, size_t length)
|
||||
|
||||
Finalize the current MAC computation and compare the result to the passed
|
||||
``mac``. Returns ``true``, if the verification is successful and false
|
||||
otherwise.
|
||||
|
||||
|
||||
Code Examples
|
||||
------------------------
|
||||
|
||||
The following example computes an HMAC with a random key then verifies the tag.
|
||||
|
||||
.. literalinclude:: /../src/examples/hmac.cpp
|
||||
:language: cpp
|
||||
|
||||
The following example code computes a AES-256 GMAC and subsequently verifies the
|
||||
tag. Unlike most other MACs, GMAC requires a nonce *which must not repeat or
|
||||
all security is lost*.
|
||||
|
||||
.. literalinclude:: /../src/examples/gmac.cpp
|
||||
:language: cpp
|
||||
|
||||
The following example code computes a valid AES-128 CMAC tag and modifies the
|
||||
data to demonstrate a MAC verification failure.
|
||||
|
||||
.. literalinclude:: /../src/examples/cmac.cpp
|
||||
:language: cpp
|
||||
|
||||
Available MACs
|
||||
------------------------------------------
|
||||
|
||||
Currently the following MAC algorithms are available in Botan. In new code,
|
||||
default to HMAC with a strong hash like SHA-256 or SHA-384.
|
||||
|
||||
CMAC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A modern CBC-MAC variant that avoids the security problems of plain CBC-MAC.
|
||||
Approved by NIST. Also sometimes called OMAC.
|
||||
|
||||
Available if ``BOTAN_HAS_CMAC`` is defined.
|
||||
|
||||
GMAC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
GMAC is related to the GCM authenticated cipher mode. It is quite slow unless
|
||||
hardware support for carryless multiplications is available. A new nonce
|
||||
must be used with **each** message authenticated, or otherwise all security is
|
||||
lost.
|
||||
|
||||
Available if ``BOTAN_HAS_GMAC`` is defined.
|
||||
|
||||
.. warning::
|
||||
Due to the nonce requirement, GMAC is exceptionally fragile. Avoid it unless
|
||||
absolutely required.
|
||||
|
||||
HMAC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A message authentication code based on a hash function. Very commonly used.
|
||||
|
||||
Available if ``BOTAN_HAS_HMAC`` is defined.
|
||||
|
||||
KMAC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
A SHA-3 derived message authentication code defined by NIST in SP 800-185.
|
||||
|
||||
There are two variants, ``KMAC-128`` and ``KMAC-256``. Both take a parameter
|
||||
which specifies the output length in bits, for example ``KMAC-128(256)``.
|
||||
|
||||
Available if ``BOTAN_HAS_KMAC`` is defined.
|
||||
|
||||
Poly1305
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A polynomial mac (similar to GMAC). Very fast, but tricky to use safely. Forms
|
||||
part of the ChaCha20Poly1305 AEAD mode. A new key must be used for **each**
|
||||
message, or all security is lost.
|
||||
|
||||
Available if ``BOTAN_HAS_POLY1305`` is defined.
|
||||
|
||||
.. warning::
|
||||
Due to the nonce requirement, Poly1305 is exceptionally fragile. Avoid it unless
|
||||
absolutely required.
|
||||
|
||||
SipHash
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A modern and very fast PRF. Produces only a 64-bit output. Defaults to
|
||||
"SipHash(2,4)" which is the recommended configuration, using 2 rounds for each
|
||||
input block and 4 rounds for finalization.
|
||||
|
||||
Available if ``BOTAN_HAS_SIPHASH`` is defined.
|
||||
|
||||
X9.19-MAC
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A CBC-MAC variant sometimes used in finance. Always uses DES.
|
||||
Sometimes called the "DES retail MAC", also standardized in ISO 9797-1.
|
||||
|
||||
It is slow and has known attacks. Avoid unless required.
|
||||
|
||||
Available if ``BOTAN_HAS_X919_MAC`` is defined.
|
@ -1,98 +0,0 @@
|
||||
One Time Passwords
|
||||
========================
|
||||
|
||||
.. versionadded:: 2.2.0
|
||||
|
||||
One time password schemes are a user authentication method that relies on a
|
||||
fixed secret key which is used to derive a sequence of short passwords, each of
|
||||
which is accepted only once. Commonly this is used to implement two-factor
|
||||
authentication (2FA), where the user authenticates using both a conventional
|
||||
password (or a public key signature) and an OTP generated by a small device such
|
||||
as a mobile phone.
|
||||
|
||||
Botan implements the HOTP and TOTP schemes from RFC 4226 and 6238.
|
||||
|
||||
Since the range of possible OTPs is quite small, applications must rate limit
|
||||
OTP authentication attempts to some small number per second. Otherwise an attacker
|
||||
could quickly try all 1000000 6-digit OTPs in a brief amount of time.
|
||||
|
||||
HOTP
|
||||
^^^^^^
|
||||
|
||||
HOTP generates OTPs that are a short numeric sequence, between 6 and 8 digits
|
||||
(most applications use 6 digits), created using the HMAC of a 64-bit counter
|
||||
value. If the counter ever repeats the OTP will also repeat, thus both parties
|
||||
must assure the counter only increments and is never repeated or
|
||||
decremented. Thus both client and server must keep track of the next counter
|
||||
expected.
|
||||
|
||||
Anyone with access to the client-specific secret key can authenticate as that
|
||||
client, so it should be treated with the same security consideration as would be
|
||||
given to any other symmetric key or plaintext password.
|
||||
|
||||
.. cpp:class:: HOTP
|
||||
|
||||
Implement counter-based OTP
|
||||
|
||||
.. cpp:function:: HOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", size_t digits = 6)
|
||||
|
||||
Initialize an HOTP instance with a secret key (specific to each client),
|
||||
a hash algorithm (must be SHA-1, SHA-256, or SHA-512), and the number of
|
||||
digits with each OTP (must be 6, 7, or 8).
|
||||
|
||||
In RFC 4226, HOTP is only defined with SHA-1, but many HOTP
|
||||
implementations support SHA-256 as an extension. The collision attacks
|
||||
on SHA-1 do not have any known effect on HOTP's security.
|
||||
|
||||
.. cpp:function:: uint32_t generate_hotp(uint64_t counter)
|
||||
|
||||
Return the OTP associated with a specific counter value.
|
||||
|
||||
.. cpp:function:: std::pair<bool,uint64_t> verify_hotp(uint32_t otp, \
|
||||
uint64_t starting_counter, size_t resync_range = 0)
|
||||
|
||||
Check if a provided OTP matches the one that should be generated for
|
||||
the specified counter.
|
||||
|
||||
The *starting_counter* should be the counter of the last successful
|
||||
authentication plus 1. If *resync_resync* is greater than 0, some number
|
||||
of counter values above *starting_counter* will also be checked if
|
||||
necessary. This is useful for instance when a client mistypes an OTP on
|
||||
entry; the authentication will fail so the server will not update its
|
||||
counter, but the client device will subsequently show the OTP for the
|
||||
next counter. Depending on the environment a *resync_range* of 3 to 10
|
||||
might be appropriate.
|
||||
|
||||
Returns a pair of (is_valid,next_counter_to_use). If the OTP is invalid
|
||||
then always returns (false,starting_counter), since the last successful
|
||||
authentication counter has not changed.
|
||||
|
||||
|
||||
TOTP
|
||||
^^^^^^^^^^
|
||||
|
||||
TOTP is based on the same algorithm as HOTP, but instead of a counter a
|
||||
timestamp is used.
|
||||
|
||||
.. cpp:class:: TOTP
|
||||
|
||||
.. cpp:function:: TOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", \
|
||||
size_t digits = 6, size_t time_step = 30)
|
||||
|
||||
Setup to perform TOTP authentication using secret key *key*.
|
||||
|
||||
.. cpp:function:: uint32_t generate_totp(std::chrono::system_clock::time_point time_point)
|
||||
|
||||
.. cpp:function:: uint32_t generate_totp(uint64_t unix_time)
|
||||
|
||||
Generate and return a TOTP code based on a timestamp.
|
||||
|
||||
.. cpp:function:: bool verify_totp(uint32_t otp, std::chrono::system_clock::time_point time, \
|
||||
size_t clock_drift_accepted = 0)
|
||||
|
||||
.. cpp:function:: bool verify_totp(uint32_t otp, uint64_t unix_time, \
|
||||
size_t clock_drift_accepted = 0)
|
||||
|
||||
Return true if the provided OTP code is correct for the provided
|
||||
timestamp. If required, use *clock_drift_accepted* to deal with
|
||||
the client and server having slightly different clocks.
|
@ -1,215 +0,0 @@
|
||||
Password Hashing
|
||||
========================================
|
||||
|
||||
Storing passwords for user authentication purposes in plaintext is the
|
||||
simplest but least secure method; when an attacker compromises the
|
||||
database in which the passwords are stored, they immediately gain
|
||||
access to all of them. Often passwords are reused among multiple
|
||||
services or machines, meaning once a password to a single service is
|
||||
known an attacker has a substantial head start on attacking other
|
||||
machines.
|
||||
|
||||
The general approach is to store, instead of the password, the output
|
||||
of a one way function of the password. Upon receiving an
|
||||
authentication request, the authenticating party can recompute the one way
|
||||
function and compare the value just computed with the one that was
|
||||
stored. If they match, then the authentication request succeeds. But
|
||||
when an attacker gains access to the database, they only have the
|
||||
output of the one way function, not the original password.
|
||||
|
||||
Common hash functions such as SHA-256 are one way, but used alone they
|
||||
have problems for this purpose. What an attacker can do, upon gaining
|
||||
access to such a stored password database, is hash common dictionary
|
||||
words and other possible passwords, storing them in a list. Then he
|
||||
can search through his list; if a stored hash and an entry in his list
|
||||
match, then he has found the password. Even worse, this can happen
|
||||
*offline*: an attacker can begin hashing common passwords days,
|
||||
months, or years before ever gaining access to the database. In
|
||||
addition, if two users choose the same password, the one way function
|
||||
output will be the same for both of them, which will be visible upon
|
||||
inspection of the database.
|
||||
|
||||
There are two solutions to these problems: salting and
|
||||
iteration. Salting refers to including, along with the password, a
|
||||
randomly chosen value which perturbs the one way function. Salting can
|
||||
reduce the effectiveness of offline dictionary generation, because for
|
||||
each potential password, an attacker would have to compute the one way
|
||||
function output for all possible salts. It also prevents the same
|
||||
password from producing the same output, as long as the salts do not
|
||||
collide. Choosing n-bit salts randomly, salt collisions become likely
|
||||
only after about 2\ :sup:\ `(n/2)` salts have been generated. Choosing a
|
||||
large salt (say 80 to 128 bits) ensures this is very unlikely. Note
|
||||
that in password hashing salt collisions are unfortunate, but not
|
||||
fatal - it simply allows the attacker to attack those two passwords in
|
||||
parallel easier than they would otherwise be able to.
|
||||
|
||||
The other approach, iteration, refers to the general technique of
|
||||
forcing multiple one way function evaluations when computing the
|
||||
output, to slow down the operation. For instance if hashing a single
|
||||
password requires running SHA-256 100,000 times instead of just once,
|
||||
that will slow down user authentication by a factor of 100,000, but
|
||||
user authentication happens quite rarely, and usually there are more
|
||||
expensive operations that need to occur anyway (network and database
|
||||
I/O, etc). On the other hand, an attacker who is attempting to break a
|
||||
database full of stolen password hashes will be seriously
|
||||
inconvenienced by a factor of 100,000 slowdown; they will be able to
|
||||
only test at a rate of .0001% of what they would without iterations
|
||||
(or, equivalently, will require 100,000 times as many zombie botnet
|
||||
hosts).
|
||||
|
||||
Memory usage while checking a password is also a consideration; if the
|
||||
computation requires using a certain minimum amount of memory, then an
|
||||
attacker can become memory-bound, which may in particular make
|
||||
customized cracking hardware more expensive. Some password hashing
|
||||
designs, such as scrypt, explicitly attempt to provide this. The
|
||||
bcrypt approach requires over 4 KiB of RAM (for the Blowfish key
|
||||
schedule) and may also make some hardware attacks more expensive.
|
||||
|
||||
Botan provides three techniques for password hashing: Argon2, bcrypt, and
|
||||
passhash9 (based on PBKDF2).
|
||||
|
||||
Argon2
|
||||
----------------------------------------
|
||||
|
||||
.. versionadded:: 2.11.0
|
||||
|
||||
Argon2 is the winner of the PHC (Password Hashing Competition) and provides
|
||||
a tunable memory hard password hash. It has a standard string encoding, which looks like::
|
||||
|
||||
"$argon2i$v=19$m=8192,t=10,p=3$YWFhYWFhYWE$itkWB9ODqTd85wUsoib7pfpVTNGMOu0ZJan1odl25V8"
|
||||
|
||||
Argon2 has three tunable parameters: ``M``, ``p``, and ``t``. ``M`` gives the
|
||||
total memory consumption of the algorithm in kilobytes. Increasing ``p``
|
||||
increases the available parallelism of the computation. The ``t`` parameter
|
||||
gives the number of passes which are made over the data.
|
||||
|
||||
There are three variants of Argon2, namely Argon2d, Argon2i and Argon2id.
|
||||
Argon2d uses data dependent table lookups with may leak information about the
|
||||
password via side channel attacks, and is **not recommended** for password
|
||||
hashing. Argon2i uses data independent table lookups and is immune to these
|
||||
attacks, but at the cost of requiring higher ``t`` for security. Argon2id uses a
|
||||
hybrid approach which is thought to be highly secure. The algorithm designers
|
||||
recommend using Argon2id with ``t`` and ``p`` both equal to 1 and ``M`` set to
|
||||
the largest amount of memory usable in your environment.
|
||||
|
||||
.. cpp:function:: std::string argon2_generate_pwhash(const char* password, size_t password_len, \
|
||||
RandomNumberGenerator& rng, \
|
||||
size_t p, size_t M, size_t t, \
|
||||
size_t y = 2, size_t salt_len = 16, size_t output_len = 32)
|
||||
|
||||
Generate an Argon2 hash of the specified password. The ``y`` parameter specifies
|
||||
the variant: 0 for Argon2d, 1 for Argon2i, and 2 for Argon2id.
|
||||
|
||||
.. cpp:function:: bool argon2_check_pwhash(const char* password, size_t password_len, \
|
||||
const std::string& hash)
|
||||
|
||||
Verify an Argon2 password hash against the provided password. Returns false if
|
||||
the input hash seems malformed or if the computed hash does not match.
|
||||
|
||||
Bcrypt
|
||||
----------------------------------------
|
||||
|
||||
`Bcrypt <https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf>`_ is a
|
||||
password hashing scheme originally designed for use in OpenBSD, but numerous
|
||||
other implementations exist. It is made available by including ``bcrypt.h``.
|
||||
|
||||
It has the advantage that it requires a small amount (4K) of fast RAM
|
||||
to compute, which can make hardware password cracking somewhat more
|
||||
expensive.
|
||||
|
||||
Bcrypt provides outputs that look like this::
|
||||
|
||||
"$2a$12$7KIYdyv8Bp32WAvc.7YvI.wvRlyVn0HP/EhPmmOyMQA4YKxINO0p2"
|
||||
|
||||
.. note::
|
||||
|
||||
Due to the design of bcrypt, the password is effectively truncated at 72
|
||||
characters; further characters are ignored and do not change the hash. To
|
||||
support longer passwords, one common approach is to pre-hash the password
|
||||
with SHA-256, then run bcrypt using the hex or base64 encoding of the hash as
|
||||
the password. (Many bcrypt implementations truncate the password at the first
|
||||
NULL character, so hashing the raw binary SHA-256 may cause problems. Botan's
|
||||
bcrypt implementation will hash whatever values are given in the
|
||||
``std::string`` including any embedded NULLs so this is not an issue, but
|
||||
might cause interop problems if another library needs to validate the
|
||||
password hashes.)
|
||||
|
||||
.. cpp:function:: std::string generate_bcrypt(const std::string& password, \
|
||||
RandomNumberGenerator& rng, \
|
||||
uint16_t work_factor = 12, \
|
||||
char bcrypt_version = "a")
|
||||
|
||||
Takes the password to hash, a rng, and a work factor.
|
||||
The resulting password hash is returned as a string.
|
||||
|
||||
Higher work factors increase the amount of time the algorithm runs,
|
||||
increasing the cost of cracking attempts. The increase is exponential, so a
|
||||
work factor of 12 takes roughly twice as long as work factor 11. The default
|
||||
work factor was set to 10 up until the 2.8.0 release.
|
||||
|
||||
It is recommended to set the work factor as high as your system can tolerate
|
||||
(from a performance and latency perspective) since higher work factors greatly
|
||||
improve the security against GPU-based attacks. For example, for protecting
|
||||
high value administrator passwords, consider using work factor 15 or 16; at
|
||||
these work factors each bcrypt computation takes several seconds. Since admin
|
||||
logins will be relatively uncommon, it might be acceptable for each login
|
||||
attempt to take some time. As of 2018, a good password cracking rig (with 8
|
||||
NVIDIA 1080 cards) can attempt about 1 billion bcrypt computations per month
|
||||
for work factor 13. For work factor 12, it can do twice as many. For work
|
||||
factor 15, it can do only one quarter as many attempts.
|
||||
|
||||
Due to bugs affecting various implementations of bcrypt, several different
|
||||
variants of the algorithm are defined. As of 2.7.0 Botan supports generating
|
||||
(or checking) the 2a, 2b, and 2y variants. Since Botan has never been
|
||||
affected by any of the bugs which necessitated these version upgrades, all
|
||||
three versions are identical beyond the version identifier. Which variant to
|
||||
use is controlled by the ``bcrypt_version`` argument.
|
||||
|
||||
The bcrypt work factor must be at least 4 (though at this work factor bcrypt
|
||||
is not very secure). The bcrypt format allows up to 31, but Botan currently
|
||||
rejects all work factors greater than 18 since even that work factor requires
|
||||
roughly 15 seconds of computation on a fast machine.
|
||||
|
||||
.. cpp:function:: bool check_bcrypt(const std::string& password, \
|
||||
const std::string& hash)
|
||||
|
||||
Takes a password and a bcrypt output and returns true if the
|
||||
password is the same as the one that was used to generate the
|
||||
bcrypt hash.
|
||||
|
||||
.. _passhash9:
|
||||
|
||||
Passhash9
|
||||
----------------------------------------
|
||||
|
||||
Botan also provides a password hashing technique called passhash9, in
|
||||
``passhash9.h``, which is based on PBKDF2.
|
||||
|
||||
Passhash9 hashes look like::
|
||||
|
||||
"$9$AAAKxwMGNPSdPkOKJS07Xutm3+1Cr3ytmbnkjO6LjHzCMcMQXvcT"
|
||||
|
||||
This function should be secure with the proper parameters, and will remain in
|
||||
the library for the foreseeable future, but it is specific to Botan rather than
|
||||
being a widely used password hash. Prefer bcrypt or Argon2.
|
||||
|
||||
.. warning::
|
||||
|
||||
This password format string ("$9$") conflicts with the format used
|
||||
for scrypt password hashes on Cisco systems.
|
||||
|
||||
.. cpp:function:: std::string generate_passhash9(const std::string& password, \
|
||||
RandomNumberGenerator& rng, uint16_t work_factor = 15, uint8_t alg_id = 4)
|
||||
|
||||
Functions much like ``generate_bcrypt``. The last parameter,
|
||||
``alg_id``, specifies which PRF to use. Currently defined values are
|
||||
0: HMAC(SHA-1), 1: HMAC(SHA-256), 2: CMAC(Blowfish), 3: HMAC(SHA-384), 4: HMAC(SHA-512)
|
||||
|
||||
The work factor must be greater than zero and less than 512. This performs
|
||||
10000 * ``work_factor`` PBKDF2 iterations, using 96 bits of salt taken from
|
||||
``rng``. Using work factor of 10 or more is recommended.
|
||||
|
||||
.. cpp:function:: bool check_passhash9(const std::string& password, \
|
||||
const std::string& hash)
|
||||
|
||||
Functions much like ``check_bcrypt``
|
@ -1,294 +0,0 @@
|
||||
|
||||
.. _pbkdf:
|
||||
|
||||
Password Based Key Derivation
|
||||
========================================
|
||||
|
||||
Often one needs to convert a human readable password into a cryptographic
|
||||
key. It is useful to slow down the computation of these computations in order to
|
||||
reduce the speed of brute force search, thus they are parameterized in some
|
||||
way which allows their required computation to be tuned.
|
||||
|
||||
PasswordHash
|
||||
--------------
|
||||
|
||||
.. versionadded:: 2.8.0
|
||||
|
||||
This API, declared in ``pwdhash.h``, has two classes, ``PasswordHashFamily``
|
||||
representing the general algorithm, such as "PBKDF2(SHA-256)", or "Scrypt", and
|
||||
``PasswordHash`` representing a specific instance of the problem which is fully
|
||||
specified with all parameters (say "Scrypt" with ``N`` = 8192, ``r`` = 64, and
|
||||
``p`` = 8) and which can be used to derive keys.
|
||||
|
||||
.. cpp:class:: PasswordHash
|
||||
|
||||
.. cpp:function:: void hash(std::span<uint8_t> out, \
|
||||
std::string_view password, \
|
||||
std::span<uint8> salt)
|
||||
|
||||
Derive a key from the specified *password* and *salt*, placing it into *out*.
|
||||
|
||||
.. cpp:function:: void hash(std::span<uint8_t> out, \
|
||||
std::string_view password, \
|
||||
std::span<const uint8> salt, \
|
||||
std::span<const uint8> ad, \
|
||||
std::span<const uint8> key)
|
||||
|
||||
Derive a key from the specified *password*, *salt*, associated data (*ad*), and
|
||||
secret *key*, placing it into *out*. The *ad* and *key* are both allowed
|
||||
to be empty. Currently non-empty AD/key is only supported with Argon2.
|
||||
|
||||
.. cpp:function:: void 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
|
||||
|
||||
Same functionality as the 3 argument variant of :cpp:func:`PasswordHash::hash`.
|
||||
|
||||
.. cpp:function:: void 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 uint8_t ad[], size_t ad_len, \
|
||||
const uint8_t key[], size_t key_len) const
|
||||
|
||||
Same functionality as the 5 argument variant of :cpp:func:`PasswordHash::hash`.
|
||||
|
||||
.. cpp:function:: std::string to_string() const
|
||||
|
||||
Return a descriptive string including the parameters (iteration count, etc)
|
||||
|
||||
.. cpp:function:: size_t iterations() const
|
||||
|
||||
Return the iteration parameter
|
||||
|
||||
.. cpp:function:: size_t memory_param() const
|
||||
|
||||
Return the memory usage parameter, or 0 if the algorithm does not offer
|
||||
a memory usage option.
|
||||
|
||||
.. cpp:function:: size_t parallelism() const
|
||||
|
||||
Returns the parallelism parameter, or 0 if the algorithm does not offer a
|
||||
parallelism option.
|
||||
|
||||
.. cpp:function:: size_t total_memory_usage() const
|
||||
|
||||
Return a guesstimate of the total number of bytes of memory consumed when
|
||||
running this algorithm. If the function is not intended to be memory-hard
|
||||
and uses an effictively fixed amount of memory when running, this function
|
||||
returns 0.
|
||||
|
||||
.. cpp:function:: bool supports_keyed_operation() const
|
||||
|
||||
Returns true if this password hash supports supplying a secret key
|
||||
to :cpp:func:`PasswordHash::hash`.
|
||||
|
||||
.. cpp:function:: bool supports_associated_data() const
|
||||
|
||||
Returns true if this password hash supports supplying associated data
|
||||
to :cpp:func:`PasswordHash::hash`.
|
||||
|
||||
The ``PasswordHashFamily`` creates specific instances of ``PasswordHash``:
|
||||
|
||||
.. cpp:class:: PasswordHashFamily
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<PasswordHashFamily> create(const std::string& what)
|
||||
|
||||
For example "PBKDF2(SHA-256)", "Scrypt", "Argon2id". Returns null if the
|
||||
algorithm is not available.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<PasswordHash> default_params() const
|
||||
|
||||
Create a default instance of the password hashing algorithm. Be warned the
|
||||
value returned here may change from release to release.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<PasswordHash> tune( \
|
||||
size_t output_len, \
|
||||
std::chrono::milliseconds msec, \
|
||||
size_t max_memory_usage_mb = 0, \
|
||||
std::chrono::milliseconds tuning_msec = std::chrono::milliseconds(10)) const
|
||||
|
||||
Return a password hash instance tuned to run for approximately ``msec``
|
||||
milliseconds when producing an output of length ``output_len``. (Accuracy
|
||||
may vary, use the command line utility ``botan pbkdf_tune`` to check.)
|
||||
|
||||
The parameters will be selected to use at most *max_memory_usage_mb* megabytes
|
||||
of memory, or if left as zero any size is allowed.
|
||||
|
||||
This function works by runing a short tuning loop to estimate the
|
||||
performance of the algorithm, then scaling the parameters appropriately to
|
||||
hit the target size. The length of time the tuning loop runs can be
|
||||
controlled using the *tuning_msec* parameter.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<PasswordHash> from_params( \
|
||||
size_t i1, size_t i2 = 0, size_t i3 = 0) const
|
||||
|
||||
Create a password hash using some scheme specific format. Parameters are as follows:
|
||||
|
||||
* For PBKDF2, PGP-S2K, and Bcrypt-PBKDF, ``i1`` is iterations
|
||||
* Scrypt uses ``i1`` == ``N``, ``i2`` == ``r``, and ``i3`` == ``p``
|
||||
* Argon2 family uses ``i1`` == ``M``, ``i2`` == ``t``, and ``i3`` == ``p``
|
||||
|
||||
All unneeded parameters should be set to 0 or left blank.
|
||||
|
||||
Code Example
|
||||
------------
|
||||
|
||||
An example demonstrating using the API to hash a password using Argon2i:
|
||||
|
||||
.. literalinclude:: /../src/examples/pwdhash.cpp
|
||||
:language: cpp
|
||||
|
||||
Available Schemes
|
||||
----------------------
|
||||
|
||||
General Recommendations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you need wide interoperability use PBKDF2 with HMAC-SHA256 and at least 50K
|
||||
iterations. If you don't, use Argon2id with p=1, t=3 and M as large as you
|
||||
can reasonably set (say 1 gigabyte).
|
||||
|
||||
You can test how long a particular PBKDF takes to execute using the cli tool
|
||||
``pbkdf_tune``::
|
||||
|
||||
$ ./botan pbkdf_tune --algo=Argon2id 500 --max-mem=192 --check
|
||||
For 500 ms selected Argon2id(196608,3,1) using 192 MiB took 413.159 msec to compute
|
||||
|
||||
This returns the parameters chosen by the fast auto-tuning algorithm, and
|
||||
because ``--check`` was supplied the hash is also executed with the full set of
|
||||
parameters and timed.
|
||||
|
||||
PBKDF2
|
||||
^^^^^^^^^^^^
|
||||
|
||||
PBKDF2 is the "standard" password derivation scheme, widely implemented in many
|
||||
different libraries. It uses HMAC internally and requires choosing a hash
|
||||
function to use. (If in doubt use SHA-256 or SHA-512). It also requires choosing
|
||||
an iteration count, which makes brute force attacks more expensive. Use *at
|
||||
least* 50000 and preferably much more. Using 250,000 would not be unreasonable.
|
||||
|
||||
Scrypt
|
||||
^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 2.7.0
|
||||
|
||||
Scrypt is a relatively newer design which is "memory hard" - in
|
||||
addition to requiring large amounts of CPU power it uses a large block
|
||||
of memory to compute the hash. This makes brute force attacks using
|
||||
ASICs substantially more expensive.
|
||||
|
||||
Scrypt has three parameters, usually termed ``N``, ``r``, and ``p``. ``N`` is
|
||||
the primary control of the workfactor, and must be a power of 2. For interactive
|
||||
logins use 32768, for protection of secret keys or backups use 1048576.
|
||||
|
||||
The ``r`` parameter controls how 'wide' the internal hashing operation is. It
|
||||
also increases the amount of memory that is used. Values from 1 to 8 are
|
||||
reasonable.
|
||||
|
||||
Setting ``p`` parameter to greater than 1 splits up the work in a way that up
|
||||
to p processors can work in parallel.
|
||||
|
||||
As a general recommendation, use ``N`` = 32768, ``r`` = 8, ``p`` = 1
|
||||
|
||||
Argon2
|
||||
^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 2.11.0
|
||||
|
||||
Argon2 is the winner of the PHC (Password Hashing Competition) and
|
||||
provides a tunable memory hard PBKDF. There are three minor variants
|
||||
of Argon2 - Argon2d, Argon2i, and Argon2id. All three are implemented.
|
||||
|
||||
Bcrypt
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 2.11.0
|
||||
|
||||
Bcrypt-PBKDF is a variant of the well known ``bcrypt`` password hashing
|
||||
function. Like ``bcrypt`` it is based around using Blowfish for the key
|
||||
expansion, which requires 4 KiB of fast random access memory, making hardware
|
||||
based attacks more expensive. Unlike Argon2 or Scrypt, the memory usage is not
|
||||
tunable.
|
||||
|
||||
This function is relatively obscure but is used for example in OpenSSH.
|
||||
Prefer Argon2 or Scrypt in new systems.
|
||||
|
||||
OpenPGP S2K
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. warning::
|
||||
|
||||
The OpenPGP algorithm is weak and strange, and should be avoided unless
|
||||
implementing OpenPGP.
|
||||
|
||||
There are some oddities about OpenPGP's S2K algorithms that are documented
|
||||
here. For one thing, it uses the iteration count in a strange manner; instead of
|
||||
specifying how many times to iterate the hash, it tells how many *bytes* should
|
||||
be hashed in total (including the salt). So the exact iteration count will
|
||||
depend on the size of the salt (which is fixed at 8 bytes by the OpenPGP
|
||||
standard, though the implementation will allow any salt size) and the size of
|
||||
the passphrase.
|
||||
|
||||
To get what OpenPGP calls "Simple S2K", set iterations to 0, and do not specify
|
||||
a salt. To get "Salted S2K", again leave the iteration count at 0, but give an
|
||||
8-byte salt. "Salted and Iterated S2K" requires an 8-byte salt and some
|
||||
iteration count (this should be significantly larger than the size of the
|
||||
longest passphrase that might reasonably be used; somewhere from 1024 to 65536
|
||||
would probably be about right). Using both a reasonably sized salt and a large
|
||||
iteration count is highly recommended to prevent password guessing attempts.
|
||||
|
||||
PBKDF
|
||||
---------
|
||||
|
||||
:cpp:class:`PBKDF` is the older API for this functionality, presented in header
|
||||
``pbkdf.h``. It only supports PBKDF2 and the PGP S2K algorithm, not
|
||||
Scrypt, Argon2, or bcrypt. This interface is deprecated and will be removed
|
||||
in a future major release.
|
||||
|
||||
In addition, this API requires the passphrase be entered as a
|
||||
``std::string``, which means the secret will be stored in memory that
|
||||
will not be zeroed.
|
||||
|
||||
.. cpp:class:: PBKDF
|
||||
|
||||
.. cpp:function:: static std::unique_ptr<PBKDF> create(const std::string& algo_spec, \
|
||||
const std::string& provider = "")
|
||||
|
||||
Return a newly created PBKDF object. The name should be in the
|
||||
format "PBKDF2(HASHNAME)", "PBKDF2(HMAC(HASHNAME))", or
|
||||
"OpenPGP-S2K". Returns null if the algorithm is not available.
|
||||
|
||||
.. cpp:function:: void pbkdf_iterations(uint8_t out[], size_t out_len, \
|
||||
const std::string& passphrase, \
|
||||
const uint8_t salt[], size_t salt_len, \
|
||||
size_t iterations) const
|
||||
|
||||
Run the PBKDF algorithm for the specified number of iterations,
|
||||
with the given salt, and write output to the buffer.
|
||||
|
||||
.. cpp:function:: void pbkdf_timed(uint8_t out[], size_t out_len, \
|
||||
const std::string& passphrase, \
|
||||
const uint8_t salt[], size_t salt_len, \
|
||||
std::chrono::milliseconds msec, \
|
||||
size_t& iterations) const
|
||||
|
||||
Choose (via short run-time benchmark) how many iterations to perform
|
||||
in order to run for roughly msec milliseconds. Writes the number
|
||||
of iterations used to reference argument.
|
||||
|
||||
.. cpp:function:: OctetString derive_key( \
|
||||
size_t output_len, const std::string& passphrase, \
|
||||
const uint8_t* salt, size_t salt_len, \
|
||||
size_t iterations) const
|
||||
|
||||
Computes a key from *passphrase* and the *salt* (of length
|
||||
*salt_len* bytes) using an algorithm-specific interpretation of
|
||||
*iterations*, producing a key of length *output_len*.
|
||||
|
||||
Use an iteration count of at least 10000. The salt should be
|
||||
randomly chosen by a good random number generator (see
|
||||
:ref:`random_number_generators` for how), or at the very least
|
||||
unique to this usage of the passphrase.
|
||||
|
||||
If you call this function again with the same parameters, you will
|
||||
get the same key.
|
@ -1,944 +0,0 @@
|
||||
.. _pkcs11:
|
||||
|
||||
PKCS#11
|
||||
========================================
|
||||
|
||||
.. versionadded:: 1.11.31
|
||||
|
||||
|
|
||||
|
||||
PKCS#11 is a platform-independent interface for accessing smart cards and
|
||||
hardware security modules (HSM). Vendors of PKCS#11 compatible devices usually
|
||||
provide a so called middleware or "PKCS#11 module" which implements the PKCS#11
|
||||
standard. This middleware translates calls from the platform-independent PKCS#11
|
||||
API to device specific calls. So application developers don't have to write smart card
|
||||
or HSM specific code for each device they want to support.
|
||||
|
||||
.. note::
|
||||
|
||||
The Botan PKCS#11 interface is implemented against version v2.40 of the standard.
|
||||
|
||||
Botan wraps the C PKCS#11 API to provide a C++ PKCS#11 interface. This is done
|
||||
in two levels of abstraction: a low level API (see :ref:`pkcs11_low_level`) and
|
||||
a high level API (see :ref:`pkcs11_high_level`). The low level API provides
|
||||
access to all functions that are specified by the standard. The high level API
|
||||
represents an object oriented approach to use PKCS#11 compatible devices but
|
||||
only provides a subset of the functions described in the standard.
|
||||
|
||||
To use the PKCS#11 implementation the ``pkcs11`` module has to be enabled.
|
||||
|
||||
.. note::
|
||||
|
||||
Both PKCS#11 APIs live in the namespace ``Botan::PKCS11``
|
||||
|
||||
.. _pkcs11_low_level:
|
||||
|
||||
Low Level API
|
||||
----------------------------------------
|
||||
|
||||
The PKCS#11 standards committee provides header files (``pkcs11.h``, ``pkcs11f.h`` and
|
||||
``pkcs11t.h``) which define the PKCS#11 API in the C programming language. These
|
||||
header files could be used directly to access PKCS#11 compatible smart cards or
|
||||
HSMs. The external header files are shipped with Botan in version v2.4 of the standard. The PKCS#11 low
|
||||
level API wraps the original PKCS#11 API, but still allows to access all functions described in the
|
||||
standard and has the advantage that it is a C++ interface with features like RAII, exceptions
|
||||
and automatic memory management.
|
||||
|
||||
The low level API is implemented by the :cpp:class:`LowLevel` class and can be accessed by
|
||||
including the header ``botan/p11.h``.
|
||||
|
||||
Preface
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
All constants that belong together in the PKCS#11 standard are grouped into C++
|
||||
enum classes. For example the different user types are grouped in the
|
||||
:cpp:enum:`UserType` enumeration:
|
||||
|
||||
.. cpp:enum-class:: UserType : CK_USER_TYPE
|
||||
|
||||
.. cpp:enumerator:: UserType::SO = CKU_SO
|
||||
.. cpp:enumerator:: UserType::User = CKU_USER
|
||||
.. cpp:enumerator:: UserType::ContextSpecific = CKU_CONTEXT_SPECIFIC
|
||||
|
||||
Additionally, all types that are used by the low or high level API are mapped by
|
||||
type aliases to more C++ like names. For instance:
|
||||
|
||||
.. cpp:type:: FunctionListPtr = CK_FUNCTION_LIST_PTR
|
||||
|
||||
.. rubric:: C-API Wrapping
|
||||
|
||||
There is at least one method in the :cpp:class:`LowLevel` class that corresponds to a PKCS#11
|
||||
function. For example the :cpp:func:`C_GetSlotList` method in the :cpp:class:`LowLevel` class is defined as follows:
|
||||
|
||||
.. cpp:class:: LowLevel
|
||||
|
||||
.. cpp:function:: bool C_GetSlotList(Bbool token_present, SlotId* slot_list_ptr, Ulong* count_ptr, ReturnValue* return_value = ThrowException) const
|
||||
|
||||
The :cpp:class:`LowLevel` class calls the PKCS#11 function from the function list of the PKCS#11 module:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
|
||||
CK_ULONG_PTR pulCount )
|
||||
|
||||
Where it makes sense there is also an overload of the :cpp:class:`LowLevel` method to make usage easier and safer:
|
||||
|
||||
.. cpp:function:: bool C_GetSlotList( bool token_present, std::vector<SlotId>& slot_ids, ReturnValue* return_value = ThrowException ) const
|
||||
|
||||
With this overload the user of this API just has to pass a vector of :cpp:type:`SlotId` instead of pointers
|
||||
to preallocated memory for the slot list and the number of elements. Additionally, there is no need
|
||||
to call the method twice in order to determine the number of elements first.
|
||||
|
||||
Another example is the :cpp:func:`C_InitPIN` overload:
|
||||
|
||||
.. cpp:function:: template<typename Talloc> bool C_InitPIN( SessionHandle session, const std::vector<uint8_t, TAlloc>& pin, ReturnValue* return_value = ThrowException ) const
|
||||
|
||||
The templated ``pin`` parameter allows to pass the PIN as a ``std::vector<uint8_t>`` or a ``secure_vector<uint8_t>``.
|
||||
If used with a ``secure_vector`` it is assured that the memory is securely erased when the ``pin`` object is no longer needed.
|
||||
|
||||
Error Handling
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All possible PKCS#11 return values are represented by the enum class:
|
||||
|
||||
.. cpp:enum-class:: ReturnValue : CK_RV
|
||||
|
||||
All methods of the :cpp:class:`LowLevel` class have a default parameter ``ReturnValue* return_value = ThrowException``.
|
||||
This parameter controls the error handling of all :cpp:class:`LowLevel` methods. The default
|
||||
behavior ``return_value = ThrowException`` is to throw an exception if the method does
|
||||
not complete successfully. If a non-``NULL`` pointer is passed, ``return_value`` receives the
|
||||
return value of the PKCS#11 function and no exception is thrown. In case ``nullptr`` is
|
||||
passed as ``return_value``, the exact return value is ignored and the method just returns
|
||||
``true`` if the function succeeds and ``false`` otherwise.
|
||||
|
||||
Getting started
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
An object of this class can be accessed by the ``Module::operator->()`` method.
|
||||
|
||||
----------
|
||||
|
||||
Code Example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_low_level.cpp
|
||||
:language: cpp
|
||||
|
||||
.. _pkcs11_high_level:
|
||||
|
||||
High Level API
|
||||
----------------------------------------
|
||||
|
||||
The high level API provides access to the most commonly used PKCS#11 functionality in an
|
||||
object oriented manner. Functionality of the high level API includes:
|
||||
|
||||
* Loading/unloading of PKCS#11 modules
|
||||
* Initialization of tokens
|
||||
* Change of PIN/SO-PIN
|
||||
* Session management
|
||||
* Random number generation
|
||||
* Enumeration of objects on the token (certificates, public keys, private keys)
|
||||
* Import/export/deletion of certificates
|
||||
* Generation/import/export/deletion of RSA and EC public and private keys
|
||||
* Encryption/decryption using RSA with support for OAEP and PKCS1-v1_5 (and raw)
|
||||
* Signature generation/verification using RSA with support for PSS and PKCS1-v1_5 (and raw)
|
||||
* Signature generation/verification using ECDSA
|
||||
* Key derivation using ECDH
|
||||
|
||||
Module
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cpp:class:`Module` class represents a PKCS#11 shared library (module) and is defined in
|
||||
``botan/p11_module.h``.
|
||||
|
||||
It is constructed from a a file path to a PKCS#11 module and optional :cpp:type:`C_InitializeArgs`:
|
||||
|
||||
.. cpp:class:: Module
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
Module(const std::string& file_path, C_InitializeArgs init_args =
|
||||
{ nullptr, nullptr, nullptr, nullptr, static_cast<CK_FLAGS>(Flag::OsLockingOk), nullptr })
|
||||
|
||||
It loads the shared library and calls :cpp:func:`C_Initialize` with the provided :cpp:type:`C_InitializeArgs`.
|
||||
On destruction of the object :cpp:func:`C_Finalize` is called.
|
||||
|
||||
There are two more methods in this class. One is for reloading the shared library
|
||||
and reinitializing the PKCS#11 module:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void reload(C_InitializeArgs init_args =
|
||||
{ nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr });
|
||||
|
||||
The other one is for getting general information about the PKCS#11 module:
|
||||
|
||||
.. cpp:function:: Info get_info() const
|
||||
|
||||
This function calls :cpp:func:`C_GetInfo` internally.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_module.cpp
|
||||
:language: cpp
|
||||
|
||||
Slot
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cpp:class:`Slot` class represents a PKCS#11 slot and is defined in
|
||||
``botan/p11_slot.h``.
|
||||
|
||||
A PKCS#11 slot is usually a smart card reader that potentially contains a token.
|
||||
|
||||
.. cpp:class:: Slot
|
||||
|
||||
.. cpp:function:: Slot(Module& module, SlotId slot_id)
|
||||
|
||||
To instantiate this class a reference to a :cpp:class:`Module` object and a ``slot_id`` have to be passed
|
||||
to the constructor.
|
||||
|
||||
.. cpp:function:: static std::vector<SlotId> get_available_slots(Module& module, bool token_present)
|
||||
|
||||
Retrieve available slot ids by calling this static method.
|
||||
|
||||
The parameter ``token_present`` controls whether all slots or only slots with a
|
||||
token attached are returned by this method. This method calls :cpp:func:`C_GetSlotList()`.
|
||||
|
||||
.. cpp:function:: SlotInfo get_slot_info() const
|
||||
|
||||
Returns information about the slot. Calls :cpp:func:`C_GetSlotInfo`.
|
||||
|
||||
.. cpp:function:: TokenInfo get_token_info() const
|
||||
|
||||
Obtains information about a particular token in the system. Calls :cpp:func:`C_GetTokenInfo`.
|
||||
|
||||
.. cpp:function:: std::vector<MechanismType> get_mechanism_list() const
|
||||
|
||||
Obtains a list of mechanism types supported by the slot. Calls :cpp:func:`C_GetMechanismList`.
|
||||
|
||||
.. cpp:function:: MechanismInfo get_mechanism_info(MechanismType mechanism_type) const
|
||||
|
||||
Obtains information about a particular mechanism possibly supported by a slot.
|
||||
Calls :cpp:func:`C_GetMechanismInfo`.
|
||||
|
||||
.. cpp:function:: void initialize(const std::string& label, const secure_string& so_pin) const
|
||||
|
||||
Calls :cpp:func:`C_InitToken` to initialize the token. The ``label`` must not exceed 32 bytes.
|
||||
The current PIN of the security officer must be passed in ``so_pin`` if the token
|
||||
is reinitialized or if it's a factory new token, the ``so_pin`` that is passed will initially be set.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_slot.cpp
|
||||
:language: cpp
|
||||
|
||||
Session
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cpp:class:`Session` class represents a PKCS#11 session and is defined in ``botan/p11_session.h``.
|
||||
|
||||
A session is a logical connection between an application and a token.
|
||||
|
||||
The session is passed to most other PKCS#11 operations, and must remain alive
|
||||
as long as any other PKCS#11 object which the session was passed to is still
|
||||
alive, otherwise errors or even an application crash are possible.
|
||||
In the future,
|
||||
the API may change to using ``shared_ptr`` to remove this problem.
|
||||
|
||||
.. cpp:class:: Session
|
||||
|
||||
There are two constructors to create a new session and one constructor to
|
||||
take ownership of an existing session. The destructor calls
|
||||
:cpp:func:`C_Logout` if a user is logged in to this session and always
|
||||
:cpp:func:`C_CloseSession`.
|
||||
|
||||
.. cpp:function:: Session(Slot& slot, bool read_only)
|
||||
|
||||
To initialize a session object a :cpp:class:`Slot` has to be specified on which the session
|
||||
should operate. ``read_only`` specifies whether the session should be read only or read write.
|
||||
Calls :cpp:func:`C_OpenSession`.
|
||||
|
||||
.. cpp:function:: Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback)
|
||||
|
||||
Creates a new session by passing a :cpp:class:`Slot`, session ``flags``, ``callback_data`` and a
|
||||
``notify_callback``. Calls :cpp:func:`C_OpenSession`.
|
||||
|
||||
.. cpp:function:: Session(Slot& slot, SessionHandle handle)
|
||||
|
||||
Takes ownership of an existing session by passing :cpp:class:`Slot` and a session ``handle``.
|
||||
|
||||
.. cpp:function:: SessionHandle release()
|
||||
|
||||
Returns the released :cpp:type:`SessionHandle`
|
||||
|
||||
.. cpp:function:: void login(UserType userType, const secure_string& pin)
|
||||
|
||||
Login to this session by passing :cpp:enum:`UserType` and ``pin``. Calls :cpp:func:`C_Login`.
|
||||
|
||||
.. cpp:function:: void logoff()
|
||||
|
||||
Logout from this session. Not mandatory because on destruction of the :cpp:class:`Session` object
|
||||
this is done automatically.
|
||||
|
||||
.. cpp:function:: SessionInfo get_info() const
|
||||
|
||||
Returns information about this session. Calls :cpp:func:`C_GetSessionInfo`.
|
||||
|
||||
.. cpp:function:: void set_pin(const secure_string& old_pin, const secure_string& new_pin) const
|
||||
|
||||
Calls :cpp:func:`C_SetPIN` to change the PIN of the logged in user using the ``old_pin``.
|
||||
|
||||
.. cpp:function:: void init_pin(const secure_string& new_pin)
|
||||
|
||||
Calls :cpp:func:`C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session).
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_session.cpp
|
||||
:language: cpp
|
||||
|
||||
Objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PKCS#11 objects consist of various attributes (:c:type:`CK_ATTRIBUTE`). For example :c:macro:`CKA_TOKEN`
|
||||
describes if a PKCS#11 object is a session object or a token object. The helper class :cpp:class:`AttributeContainer`
|
||||
helps with storing these attributes. The class is defined in ``botan/p11_object.h``.
|
||||
|
||||
.. cpp:class:: AttributeContainer
|
||||
|
||||
Attributes can be set in an :cpp:class:`AttributeContainer` by various ``add_`` methods:
|
||||
|
||||
.. cpp:function:: void add_class(ObjectClass object_class)
|
||||
|
||||
Add a class attribute (:c:macro:`CKA_CLASS` / :cpp:enumerator:`AttributeType::Class`)
|
||||
|
||||
.. cpp:function:: void add_string(AttributeType attribute, const std::string& value)
|
||||
|
||||
Add a string attribute (e.g. :c:macro:`CKA_LABEL` / :cpp:enumerator:`AttributeType::Label`).
|
||||
|
||||
.. cpp:function:: void AttributeContainer::add_binary(AttributeType attribute, const uint8_t* value, size_t length)
|
||||
|
||||
Add a binary attribute (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`).
|
||||
|
||||
.. cpp:function:: template<typename TAlloc> void AttributeContainer::add_binary(AttributeType attribute, const std::vector<uint8_t, TAlloc>& binary)
|
||||
|
||||
Add a binary attribute by passing a ``vector``/``secure_vector`` (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`).
|
||||
|
||||
.. cpp:function:: void AttributeContainer::add_bool(AttributeType attribute, bool value)
|
||||
|
||||
Add a bool attribute (e.g. :c:macro:`CKA_SENSITIVE` / :cpp:enumerator:`AttributeType::Sensitive`).
|
||||
|
||||
.. cpp:function:: template<typename T> void AttributeContainer::add_numeric(AttributeType attribute, T value)
|
||||
|
||||
Add a numeric attribute (e.g. :c:macro:`CKA_MODULUS_BITS` / :cpp:enumerator:`AttributeType::ModulusBits`).
|
||||
|
||||
.. rubric:: Object Properties
|
||||
|
||||
The PKCS#11 standard defines the mandatory and optional attributes for each object class.
|
||||
The mandatory and optional attribute requirements are mapped in so called property classes.
|
||||
Mandatory attributes are set in the constructor, optional attributes can be set via ``set_`` methods.
|
||||
|
||||
In the top hierarchy is the :cpp:class:`ObjectProperties` class which inherits from the :cpp:class:`AttributeContainer`.
|
||||
This class represents the common attributes of all PKCS#11 objects.
|
||||
|
||||
.. cpp:class:: ObjectProperties : public AttributeContainer
|
||||
|
||||
The constructor is defined as follows:
|
||||
|
||||
.. cpp:function:: ObjectProperties::ObjectProperties(ObjectClass object_class)
|
||||
|
||||
Every PKCS#11 object needs an object class attribute.
|
||||
|
||||
The next level defines the :cpp:class:`StorageObjectProperties` class which inherits from
|
||||
:cpp:class:`ObjectProperties`.
|
||||
|
||||
.. cpp:class:: StorageObjectProperties : public ObjectProperties
|
||||
|
||||
The only mandatory attribute is the object class, so the constructor is
|
||||
defined as follows:
|
||||
|
||||
.. cpp:function:: StorageObjectProperties::StorageObjectProperties(ObjectClass object_class)
|
||||
|
||||
But in contrast to the :cpp:class:`ObjectProperties` class there are various setter methods. For example to
|
||||
set the :cpp:enumerator:`AttributeType::Label`:
|
||||
|
||||
.. cpp:function:: void set_label(const std::string& label)
|
||||
|
||||
Sets the label description of the object (RFC2279 string).
|
||||
|
||||
The remaining hierarchy is defined as follows:
|
||||
|
||||
* :cpp:class:`DataObjectProperties` inherits from :cpp:class:`StorageObjectProperties`
|
||||
* :cpp:class:`CertificateProperties` inherits from :cpp:class:`StorageObjectProperties`
|
||||
* :cpp:class:`DomainParameterProperties` inherits from :cpp:class:`StorageObjectProperties`
|
||||
* :cpp:class:`KeyProperties` inherits from :cpp:class:`StorageObjectProperties`
|
||||
* :cpp:class:`PublicKeyProperties` inherits from :cpp:class:`KeyProperties`
|
||||
* :cpp:class:`PrivateKeyProperties` inherits from :cpp:class:`KeyProperties`
|
||||
* :cpp:class:`SecretKeyProperties` inherits from :cpp:class:`KeyProperties`
|
||||
|
||||
PKCS#11 objects themselves are represented by the :cpp:class:`Object` class.
|
||||
|
||||
.. cpp:class:: Object
|
||||
|
||||
Following constructors are defined:
|
||||
|
||||
.. cpp:function:: Object::Object(Session& session, ObjectHandle handle)
|
||||
|
||||
Takes ownership over an existing object.
|
||||
|
||||
.. cpp:function:: Object::Object(Session& session, const ObjectProperties& obj_props)
|
||||
|
||||
Creates a new object with the :cpp:class:`ObjectProperties` provided in ``obj_props``.
|
||||
|
||||
The other methods are:
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> get_attribute_value(AttributeType attribute) const
|
||||
|
||||
Returns the value of the given attribute (using :cpp:func:`C_GetAttributeValue`)
|
||||
|
||||
.. cpp:function:: void set_attribute_value(AttributeType attribute, const secure_vector<uint8_t>& value) const
|
||||
|
||||
Sets the given value for the attribute (using :cpp:func:`C_SetAttributeValue`)
|
||||
|
||||
.. cpp:function:: void destroy() const
|
||||
|
||||
Destroys the object.
|
||||
|
||||
.. cpp:function:: ObjectHandle copy(const AttributeContainer& modified_attributes) const
|
||||
|
||||
Allows to copy the object with modified attributes.
|
||||
|
||||
And static methods to search for objects:
|
||||
|
||||
.. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::vector<Attribute>& search_template)
|
||||
|
||||
Searches for all objects of the given type that match ``search_template``.
|
||||
|
||||
.. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::string& label)
|
||||
|
||||
Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`).
|
||||
|
||||
.. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::vector<uint8_t>& id)
|
||||
|
||||
Searches for all objects of the given type using the id (:c:macro:`CKA_ID`).
|
||||
|
||||
.. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::string& label, const std::vector<uint8_t>& id)
|
||||
|
||||
Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`) and id (:c:macro:`CKA_ID`).
|
||||
|
||||
.. cpp:function:: template<typename T> static std::vector<T> search(Session& session)
|
||||
|
||||
Searches for all objects of the given type.
|
||||
|
||||
.. rubric:: The ObjectFinder
|
||||
|
||||
Another way for searching objects is to use the :cpp:class:`ObjectFinder` class. This class
|
||||
manages calls to the ``C_FindObjects*`` functions: :cpp:func:`C_FindObjectsInit`, :cpp:func:`C_FindObjects`
|
||||
and :cpp:func:`C_FindObjectsFinal`.
|
||||
|
||||
.. cpp:class:: ObjectFinder
|
||||
|
||||
The constructor has the following signature:
|
||||
|
||||
.. cpp:function:: ObjectFinder::ObjectFinder(Session& session, const std::vector<Attribute>& search_template)
|
||||
|
||||
A search can be prepared with an :cpp:class:`ObjectSearcher` by passing a :cpp:class:`Session` and a ``search_template``.
|
||||
|
||||
The actual search operation is started by calling the :cpp:func:`find` method:
|
||||
|
||||
.. cpp:function:: std::vector<ObjectHandle> find(std::uint32_t max_count = 100) const
|
||||
|
||||
Starts or continues a search for token and session objects that match a template. ``max_count``
|
||||
specifies the maximum number of search results (object handles) that are returned.
|
||||
|
||||
.. cpp:function:: void finish()
|
||||
|
||||
Finishes the search operation manually to allow a new :cpp:class:`ObjectFinder` to exist.
|
||||
Otherwise the search is finished by the destructor.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_objects.cpp
|
||||
:language: cpp
|
||||
|
||||
RSA
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PKCS#11 RSA support is implemented in ``<botan/p11_rsa.h>``.
|
||||
|
||||
.. rubric:: RSA Public Keys
|
||||
|
||||
PKCS#11 RSA public keys are provided by the class :cpp:class:`PKCS11_RSA_PublicKey`. This class
|
||||
inherits from :cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. Furthermore there are two property classes defined
|
||||
to generate and import RSA public keys analogous to the other property classes described
|
||||
before: :cpp:class:`RSA_PublicKeyGenerationProperties` and :cpp:class:`RSA_PublicKeyImportProperties`.
|
||||
|
||||
.. cpp:class:: PKCS11_RSA_PublicKey : public RSA_PublicKey, public Object
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 RSA public keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props)
|
||||
|
||||
This constructor can be used to import an existing RSA public key with the :cpp:class:`RSA_PublicKeyImportProperties`
|
||||
passed in ``pubkey_props`` to the token.
|
||||
|
||||
.. rubric:: RSA Private Keys
|
||||
|
||||
The support for PKCS#11 RSA private keys is implemented in a similar way. There are two property
|
||||
classes: :cpp:class:`RSA_PrivateKeyGenerationProperties` and :cpp:class:`RSA_PrivateKeyImportProperties`. The :cpp:class:`PKCS11_RSA_PrivateKey`
|
||||
class implements the actual support for PKCS#11 RSA private keys. This class inherits from :cpp:class:`Private_Key`,
|
||||
:cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. In contrast to the public key class there is a third constructor
|
||||
to generate private keys directly on the token or in the session and one method to export private keys.
|
||||
|
||||
.. cpp:class:: PKCS11_RSA_PrivateKey : public Private_Key, public RSA_PublicKey, public Object
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 RSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props)
|
||||
|
||||
This constructor can be used to import an existing RSA private key with the :cpp:class:`RSA_PrivateKeyImportProperties`
|
||||
passed in ``priv_key_props`` to the token.
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props)
|
||||
|
||||
Generates a new PKCS#11 RSA private key with bit length provided in ``bits`` and the :cpp:class:`RSA_PrivateKeyGenerationProperties`
|
||||
passed in ``priv_key_props``.
|
||||
|
||||
.. cpp:function:: RSA_PrivateKey export_key() const
|
||||
|
||||
Returns the exported :cpp:class:`RSA_PrivateKey`.
|
||||
|
||||
PKCS#11 RSA key pairs can be generated with the following free function:
|
||||
|
||||
.. cpp:function:: PKCS11_RSA_KeyPair PKCS11::generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, const RSA_PrivateKeyGenerationProperties& priv_props)
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_rsa.cpp
|
||||
:language: cpp
|
||||
|
||||
ECDSA
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PKCS#11 ECDSA support is implemented in ``<botan/p11_ecdsa.h>``.
|
||||
|
||||
.. rubric:: ECDSA Public Keys
|
||||
|
||||
PKCS#11 ECDSA public keys are provided by the class :cpp:class:`PKCS11_ECDSA_PublicKey`. This class
|
||||
inherits from :cpp:class:`PKCS11_EC_PublicKey` and :cpp:class:`ECDSA_PublicKey`. The necessary property classes
|
||||
are defined in ``<botan/p11_ecc_key.h>``. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties`
|
||||
and :cpp:class:`EC_PublicKeyImportProperties`.
|
||||
|
||||
.. cpp:class:: PKCS11_ECDSA_PublicKey : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
|
||||
|
||||
This constructor can be used to import an existing ECDSA public key with the :cpp:class:`EC_PublicKeyImportProperties`
|
||||
passed in ``props`` to the token.
|
||||
|
||||
.. cpp:function:: ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const
|
||||
|
||||
Returns the exported :cpp:class:`ECDSA_PublicKey`.
|
||||
|
||||
.. rubric:: ECDSA Private Keys
|
||||
|
||||
The class :cpp:class:`PKCS11_ECDSA_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and implements support
|
||||
for PKCS#11 ECDSA private keys. There are two property classes for key generation
|
||||
and import: :cpp:class:`EC_PrivateKeyGenerationProperties` and :cpp:class:`EC_PrivateKeyImportProperties`.
|
||||
|
||||
.. cpp:class:: PKCS11_ECDSA_PrivateKey : public PKCS11_EC_PrivateKey
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
|
||||
|
||||
This constructor can be used to import an existing ECDSA private key with the :cpp:class:`EC_PrivateKeyImportProperties`
|
||||
passed in ``props`` to the token.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const std::vector<uint8_t>& ec_params, const EC_PrivateKeyGenerationProperties& props)
|
||||
|
||||
This constructor can be used to generate a new ECDSA private key with the :cpp:class:`EC_PrivateKeyGenerationProperties`
|
||||
passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an
|
||||
ANSI X9.62 Parameters value.
|
||||
|
||||
.. cpp:function:: ECDSA_PrivateKey export_key() const
|
||||
|
||||
Returns the exported :cpp:class:`ECDSA_PrivateKey`.
|
||||
|
||||
PKCS#11 ECDSA key pairs can be generated with the following free function:
|
||||
|
||||
.. cpp:function:: PKCS11_ECDSA_KeyPair PKCS11::generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props)
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_ecdsa.cpp
|
||||
:language: cpp
|
||||
|
||||
ECDH
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PKCS#11 ECDH support is implemented in ``<botan/p11_ecdh.h>``.
|
||||
|
||||
.. rubric:: ECDH Public Keys
|
||||
|
||||
PKCS#11 ECDH public keys are provided by the class :cpp:class:`PKCS11_ECDH_PublicKey`. This class
|
||||
inherits from :cpp:class:`PKCS11_EC_PublicKey`. The necessary property classes
|
||||
are defined in ``<botan/p11_ecc_key.h>``. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties`
|
||||
and :cpp:class:`EC_PublicKeyImportProperties`.
|
||||
|
||||
.. cpp:class:: PKCS11_ECDH_PublicKey : public PKCS11_EC_PublicKey
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
|
||||
|
||||
This constructor can be used to import an existing ECDH public key with the :cpp:class:`EC_PublicKeyImportProperties`
|
||||
passed in ``props`` to the token.
|
||||
|
||||
.. cpp:function:: ECDH_PublicKey export_key() const
|
||||
|
||||
Returns the exported :cpp:class:`ECDH_PublicKey`.
|
||||
|
||||
.. rubric:: ECDH Private Keys
|
||||
|
||||
The class :cpp:class:`PKCS11_ECDH_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and :cpp:class:`PK_Key_Agreement_Key`
|
||||
and implements support for PKCS#11 ECDH private keys. There are two
|
||||
property classes. One for key generation and one for import: :cpp:class:`EC_PrivateKeyGenerationProperties` and
|
||||
:cpp:class:`EC_PrivateKeyImportProperties`.
|
||||
|
||||
.. cpp:class:: PKCS11_ECDH_PrivateKey : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle)
|
||||
|
||||
Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the
|
||||
constructor.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
|
||||
|
||||
This constructor can be used to import an existing ECDH private key with the :cpp:class:`EC_PrivateKeyImportProperties`
|
||||
passed in ``props`` to the token.
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const std::vector<uint8_t>& ec_params, const EC_PrivateKeyGenerationProperties& props)
|
||||
|
||||
This constructor can be used to generate a new ECDH private key with the :cpp:class:`EC_PrivateKeyGenerationProperties`
|
||||
passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an
|
||||
ANSI X9.62 Parameters value.
|
||||
|
||||
.. cpp:function:: ECDH_PrivateKey export_key() const
|
||||
|
||||
Returns the exported :cpp:class:`ECDH_PrivateKey`.
|
||||
|
||||
PKCS#11 ECDH key pairs can be generated with the following free function:
|
||||
|
||||
.. cpp:function:: PKCS11_ECDH_KeyPair PKCS11::generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props)
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_ecdh.cpp
|
||||
:language: cpp
|
||||
|
||||
RNG
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The PKCS#11 RNG is defined in ``<botan/p11_randomgenerator.h>``. The class :cpp:class:`PKCS11_RNG`
|
||||
implements the :cpp:class:`Hardware_RNG` interface.
|
||||
|
||||
.. cpp:class:: PKCS11_RNG : public Hardware_RNG
|
||||
|
||||
.. cpp:function:: PKCS11_RNG(Session& session)
|
||||
|
||||
A PKCS#11 :cpp:class:`Session` must be passed to instantiate a ``PKCS11_RNG``.
|
||||
|
||||
.. cpp:function:: void randomize(uint8_t output[], std::size_t length) override
|
||||
|
||||
Calls :cpp:func:`C_GenerateRandom` to generate random data.
|
||||
|
||||
.. cpp:function:: void add_entropy(const uint8_t in[], std::size_t length) override
|
||||
|
||||
Calls :cpp:func:`C_SeedRandom` to add entropy to the random generation function of the token/middleware.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_rng.cpp
|
||||
:language: cpp
|
||||
|
||||
Token Management Functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The header file ``<botan/p11.h>`` also defines some free functions for token management:
|
||||
|
||||
.. cpp:function:: void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin)
|
||||
|
||||
Initializes a token by passing a :cpp:class:`Slot`, a ``label`` and the ``so_pin`` of the security officer.
|
||||
|
||||
.. cpp:function:: void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin)
|
||||
|
||||
Change PIN with ``old_pin`` to ``new_pin``.
|
||||
|
||||
.. cpp:function:: void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin)
|
||||
|
||||
Change SO_PIN with ``old_so_pin`` to new ``new_so_pin``.
|
||||
|
||||
.. cpp:function:: void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin)
|
||||
|
||||
Sets user ``pin`` with ``so_pin``.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_token_management.cpp
|
||||
:language: cpp
|
||||
|
||||
X.509
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The header file ``<botan/p11_x509.h>`` defines the property class :cpp:class:`X509_CertificateProperties`
|
||||
and the class :cpp:class:`PKCS11_X509_Certificate`.
|
||||
|
||||
.. cpp:class:: PKCS11_X509_Certificate : public Object, public X509_Certificate
|
||||
|
||||
.. cpp:function:: PKCS11_X509_Certificate(Session& session, ObjectHandle handle)
|
||||
|
||||
Allows to use existing certificates on the token by passing a valid :cpp:type:`ObjectHandle`.
|
||||
|
||||
.. cpp:function:: PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props)
|
||||
|
||||
Allows to import an existing X.509 certificate to the token with the :cpp:class:`X509_CertificateProperties`
|
||||
passed in ``props``.
|
||||
|
||||
----------
|
||||
|
||||
Code example:
|
||||
|
||||
.. literalinclude:: /../src/examples/pkcs11_x509.cpp
|
||||
:language: cpp
|
||||
|
||||
Tests
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The PKCS#11 tests are not executed automatically because the depend on an external
|
||||
PKCS#11 module/middleware. The test tool has to be executed with ``--pkcs11-lib=``
|
||||
followed with the path of the PKCS#11 module and a second argument which controls the
|
||||
PKCS#11 tests that are executed. Passing ``pkcs11`` will execute all PKCS#11 tests but it's
|
||||
also possible to execute only a subset with the following arguments:
|
||||
|
||||
- pkcs11-ecdh
|
||||
- pkcs11-ecdsa
|
||||
- pkcs11-lowlevel
|
||||
- pkcs11-manage
|
||||
- pkcs11-module
|
||||
- pkcs11-object
|
||||
- pkcs11-rng
|
||||
- pkcs11-rsa
|
||||
- pkcs11-session
|
||||
- pkcs11-slot
|
||||
- pkcs11-x509
|
||||
|
||||
The following PIN and SO-PIN/PUK values are used in tests:
|
||||
|
||||
- PIN 123456
|
||||
- SO-PIN/PUK 12345678
|
||||
|
||||
.. warning::
|
||||
|
||||
Unlike the CardOS (4.4, 5.0, 5.3), the aforementioned SO-PIN/PUK is
|
||||
inappropriate for Gemalto (IDPrime MD 3840) cards, as it must be a byte array
|
||||
of length 24. For this reason some of the tests for Gemalto card involving
|
||||
SO-PIN will fail. You run into a risk of exceding login attempts and as a
|
||||
result locking your card! Currently, specifying pin via command-line option
|
||||
is not implemented, and therefore the desired PIN must be modified in the
|
||||
header src/tests/test_pkcs11.h:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// SO PIN is expected to be set to "12345678" prior to running the tests
|
||||
const std::string SO_PIN = "12345678";
|
||||
const auto SO_PIN_SECVEC = Botan::PKCS11::secure_string(SO_PIN.begin(), SO_PIN.end());
|
||||
|
||||
|
||||
Tested/Supported Smartcards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You are very welcome to contribute your own test results for other testing environments or other cards.
|
||||
|
||||
|
||||
Test results
|
||||
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| Smartcard | Status | OS | Midleware | Botan | Errors |
|
||||
+=====================================+===========================================+===================================================+===================================================+===================================================+===================================================+
|
||||
| CardOS 4.4 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [50]_ |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| CardOS 5.0 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [51]_ |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [52]_ |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1903 | API Version 5.5.1 (Cryptoki v2.11) | 2.12.0 unreleased, Cryptoki v2.40 | [53]_ |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| Gemalto IDPrime MD 3840 | mostly works | Windows 10, 64-bit, version 1709 | IDGo 800, v1.2.4 (Cryptoki v2.20) | 2.4.0, Cryptoki v2.40 | [54]_ |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| SoftHSM 2.3.0 (OpenSSL 1.0.2g) | works | Windows 10, 64-bit, version 1709 | Cryptoki v2.40 | 2.4.0, Cryptoki v2.40 | |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
| SoftHSM 2.5.0 (OpenSSL 1.1.1) | works | Windows 10, 64-bit, version 1803 | Cryptoki v2.40 | 2.11.0, Cryptoki v2.40 | |
|
||||
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
|
||||
|
||||
.. [50] Failing operations for CardOS 4.4:
|
||||
|
||||
- object_copy [20]_
|
||||
|
||||
- rsa_privkey_export [21]_
|
||||
- rsa_generate_private_key [22]_
|
||||
- rsa_sign_verify [23]_
|
||||
|
||||
- ecdh_privkey_import [3]_
|
||||
- ecdh_privkey_export [2]_
|
||||
- ecdh_pubkey_import [4]_
|
||||
- ecdh_pubkey_export [4]_
|
||||
- ecdh_generate_private_key [3]_
|
||||
- ecdh_generate_keypair [3]_
|
||||
- ecdh_derive [3]_
|
||||
|
||||
- ecdsa_privkey_import [3]_
|
||||
- ecdsa_privkey_export [2]_
|
||||
- ecdsa_pubkey_import [4]_
|
||||
- ecdsa_pubkey_export [4]_
|
||||
- ecdsa_generate_private_key [3]_
|
||||
- ecdsa_generate_keypair [3]_
|
||||
- ecdsa_sign_verify [3]_
|
||||
|
||||
- rng_add_entropy [5]_
|
||||
|
||||
|
||||
.. [51] Failing operations for CardOS 5.0
|
||||
|
||||
- object_copy [20]_
|
||||
|
||||
- rsa_privkey_export [21]_
|
||||
- rsa_generate_private_key [22]_
|
||||
- rsa_sign_verify [23]_
|
||||
|
||||
- ecdh_privkey_export [2]_
|
||||
- ecdh_pubkey_import [4]_
|
||||
- ecdh_generate_private_key [32]_
|
||||
- ecdh_generate_keypair [3]_
|
||||
- ecdh_derive [33]_
|
||||
|
||||
- ecdsa_privkey_export [2]_
|
||||
- ecdsa_generate_private_key [30]_
|
||||
- ecdsa_generate_keypair [30]_
|
||||
- ecdsa_sign_verify [30]_
|
||||
|
||||
- rng_add_entropy [5]_
|
||||
|
||||
.. [52] Failing operations for CardOS 5.3
|
||||
|
||||
- object_copy [20]_
|
||||
|
||||
- rsa_privkey_export [21]_
|
||||
- rsa_generate_private_key [22]_
|
||||
- rsa_sign_verify [23]_
|
||||
|
||||
- ecdh_privkey_export [2]_
|
||||
- ecdh_pubkey_import [6]_
|
||||
- ecdh_pubkey_export [6]_
|
||||
- ecdh_generate_private_key [30]_
|
||||
- ecdh_generate_keypair [31]_
|
||||
- ecdh_derive [30]_
|
||||
|
||||
- ecdsa_privkey_export [2]_
|
||||
- ecdsa_pubkey_import [6]_
|
||||
- ecdsa_pubkey_export [6]_
|
||||
- ecdsa_generate_private_key [31]_
|
||||
- ecdsa_generate_keypair [31]_
|
||||
- ecdsa_sign_verify [34]_
|
||||
|
||||
- rng_add_entropy [5]_
|
||||
|
||||
.. [53] Failing operations for CardOS 5.3 (middelware 5.5.1)
|
||||
|
||||
- ecdh_privkey_export [2]_
|
||||
- ecdh_generate_private_key [35]_
|
||||
- ecdsa_privkey_export [2]_
|
||||
- ecdsa_generate_private_key [36]_
|
||||
- c_copy_object [4]_
|
||||
|
||||
- object_copy [4]_
|
||||
|
||||
- rng_add_entropy [5]_
|
||||
|
||||
- rsa_sign_verify [3]_
|
||||
- rsa_privkey_export [2]_
|
||||
- rsa_generate_private_key [9]_
|
||||
|
||||
.. [54] Failing operations for Gemalto IDPrime MD 3840
|
||||
|
||||
- session_login_logout [2]_
|
||||
- session_info [2]_
|
||||
- set_pin [2]_
|
||||
- initialize [2]_
|
||||
- change_so_pin [2]_
|
||||
|
||||
- object_copy [20]_
|
||||
|
||||
- rsa_generate_private_key [7]_
|
||||
- rsa_encrypt_decrypt [8]_
|
||||
- rsa_sign_verify [2]_
|
||||
|
||||
- rng_add_entropy [5]_
|
||||
|
||||
Error descriptions
|
||||
|
||||
.. [2] CKR_ARGUMENTS_BAD (0x7=7)
|
||||
.. [3] CKR_MECHANISM_INVALID (0x70=112)
|
||||
.. [4] CKR_FUNCTION_NOT_SUPPORTED (0x54=84)
|
||||
.. [5] CKR_RANDOM_SEED_NOT_SUPPORTED (0x120=288)
|
||||
.. [6] CKM_X9_42_DH_KEY_PAIR_GEN | CKR_DEVICE_ERROR (0x30=48)
|
||||
.. [7] CKR_TEMPLATE_INCONSISTENT (0xD1=209)
|
||||
.. [8] CKR_ENCRYPTED_DATA_INVALID | CKM_SHA256_RSA_PKCS (0x40=64)
|
||||
.. [9] CKR_TEMPLATE_INCOMPLETE (0xD0=208)
|
||||
|
||||
.. [20] Test fails due to unsupported copy function (CKR_FUNCTION_NOT_SUPPORTED)
|
||||
.. [21] Generating private key for extraction with property extractable fails (CKR_ARGUMENTS_BAD)
|
||||
.. [22] Generate rsa private key operation fails (CKR_TEMPLATE_INCOMPLETE)
|
||||
.. [23] Raw RSA sign-verify fails (CKR_MECHANISM_INVALID)
|
||||
|
||||
.. [30] Invalid argument Decoding error: BER: Value truncated
|
||||
.. [31] Invalid argument Decoding error: BER: Length field is to large
|
||||
.. [32] Invalid argument OS2ECP: Unknown format type 155
|
||||
.. [33] Invalid argument OS2ECP: Unknown format type 92
|
||||
.. [34] Invalid argument OS2ECP: Unknown format type 57
|
||||
.. [35] Invalid argument OS2ECP: Unknown format type 82
|
||||
.. [36] Invalid argument OS2ECP: Unknown format type 102
|
@ -1,110 +0,0 @@
|
||||
PSK Database
|
||||
======================
|
||||
|
||||
.. versionadded:: 2.4.0
|
||||
|
||||
Many applications need to store pre-shared keys (hereafter PSKs) for
|
||||
authentication purposes.
|
||||
|
||||
An abstract interface to PSK stores, along with some implementations
|
||||
of same, are provided in ``psk_db.h``
|
||||
|
||||
.. cpp:class:: PSK_Database
|
||||
|
||||
.. cpp:function:: bool is_encrypted() const
|
||||
|
||||
Returns true if (at least) the PSKs themselves are encrypted. Returns
|
||||
false if PSKs are stored in plaintext.
|
||||
|
||||
.. cpp:function:: std::set<std::string> list_names() const
|
||||
|
||||
Return the set of valid names stored in the database, ie values for which
|
||||
``get`` will return a value.
|
||||
|
||||
.. cpp:function:: void set(const std::string& name, const uint8_t psk[], size_t psk_len)
|
||||
|
||||
Save a PSK. If ``name`` already exists, the current value will be
|
||||
overwritten.
|
||||
|
||||
.. cpp:function:: secure_vector<uint8_t> get(const std::string& name) const
|
||||
|
||||
Return a value saved with ``set``. Throws an exception if ``name`` doesn't
|
||||
exist.
|
||||
|
||||
.. cpp:function:: void remove(const std::string& name)
|
||||
|
||||
Remove ``name`` from the database. If ``name`` doesn't exist, ignores the request.
|
||||
|
||||
.. cpp::function:: std::string get_str(const std::string& name) const
|
||||
|
||||
Like ``get`` but casts the return value to a string.
|
||||
|
||||
.. cpp:function:: void set_str(const std::string& name, const std::string& psk)
|
||||
|
||||
Like ``set`` but accepts the psk as a string (eg for a password).
|
||||
|
||||
.. cpp:function:: template<typename Alloc> void set_vec(const std::string& name, \
|
||||
const std::vector<uint8_t, Alloc>& psk)
|
||||
|
||||
Like ``set`` but accepting a vector.
|
||||
|
||||
The same header also provides a specific instantiation of ``PSK_Database`` which
|
||||
encrypts both names and PSKs. It must be subclassed to provide the storage.
|
||||
|
||||
.. cpp:class:: Encrypted_PSK_Database : public PSK_Database
|
||||
|
||||
.. cpp:function:: Encrypted_PSK_Database(const secure_vector<uint8_t>& master_key)
|
||||
|
||||
Initializes or opens a PSK database. The master key is used the secure the
|
||||
contents. It may be of any length. If encrypting PSKs under a passphrase,
|
||||
use a suitable key derivation scheme (such as PBKDF2) to derive the secret
|
||||
key. If the master key is lost, all PSKs stored are unrecoverable.
|
||||
|
||||
Both names and values are encrypted using NIST key wrapping (see NIST
|
||||
SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256)
|
||||
to derive two 256-bit keys, one for encrypting all names and the other to
|
||||
key an instance of HMAC(SHA-256). Values are each encrypted under an
|
||||
individual key created by hashing the encrypted name with HMAC. This
|
||||
associates the encrypted key with the name, and prevents an attacker with
|
||||
write access to the data store from taking an encrypted key associated
|
||||
with one entity and copying it to another entity.
|
||||
|
||||
Names and PSKs are both padded to the next multiple of 8 bytes, providing
|
||||
some obfuscation of the length.
|
||||
|
||||
One artifact of the names being encrypted is that is is possible to use
|
||||
multiple different master keys with the same underlying storage. Each
|
||||
master key will be responsible for a subset of the keys. An attacker who
|
||||
knows one of the keys will be able to tell there are other values
|
||||
encrypted under another key, but will not be able to tell how many other
|
||||
master keys are in use.
|
||||
|
||||
.. cpp:function:: virtual void kv_set(const std::string& index, const std::string& value) = 0
|
||||
|
||||
Save an encrypted value. Both ``index`` and ``value`` will be non-empty
|
||||
base64 encoded strings.
|
||||
|
||||
.. cpp:function:: virtual std::string kv_get(const std::string& index) const = 0
|
||||
|
||||
Return a value saved with ``kv_set``, or return the empty string.
|
||||
|
||||
.. cpp:function:: virtual void kv_del(const std::string& index) = 0
|
||||
|
||||
Remove a value saved with ``kv_set``.
|
||||
|
||||
.. cpp:function:: virtual std::set<std::string> kv_get_all() const = 0
|
||||
|
||||
Return all active names (ie values for which ``kv_get`` will return a
|
||||
non-empty string).
|
||||
|
||||
A subclass of ``Encrypted_PSK_Database`` which stores data in a SQL database
|
||||
is also available.
|
||||
|
||||
.. cpp:class:: Encrypted_PSK_Database_SQL : public Encrypted_PSK_Database
|
||||
|
||||
.. cpp:function:: Encrypted_PSK_Database_SQL(const secure_vector<uint8_t>& master_key, \
|
||||
std::shared_ptr<SQL_Database> db, \
|
||||
const std::string& table_name)
|
||||
|
||||
Creates or uses the named table in ``db``. The SQL schema of the table is
|
||||
``(psk_name TEXT PRIMARY KEY, psk_value TEXT)``.
|
File diff suppressed because it is too large
Load Diff
@ -1,667 +0,0 @@
|
||||
|
||||
Python Binding
|
||||
========================================
|
||||
|
||||
.. versionadded:: 1.11.14
|
||||
|
||||
.. highlight:: python
|
||||
|
||||
.. py:module:: botan3
|
||||
|
||||
The Python binding is based on the `ffi` module of botan and the
|
||||
`ctypes` module of the Python standard library.
|
||||
|
||||
The versioning of the Python module follows the major versioning of
|
||||
the C++ library. So for Botan 2, the module is named ``botan2`` while
|
||||
for Botan 3 it is ``botan3``.
|
||||
|
||||
Versioning
|
||||
----------------------------------------
|
||||
.. py:function:: version_major()
|
||||
|
||||
Returns the major number of the library version.
|
||||
|
||||
.. py:function:: version_minor()
|
||||
|
||||
Returns the minor number of the library version.
|
||||
|
||||
.. py:function:: version_patch()
|
||||
|
||||
Returns the patch number of the library version.
|
||||
|
||||
.. py:function:: version_string()
|
||||
|
||||
Returns a free form version string for the library
|
||||
|
||||
Random Number Generators
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: RandomNumberGenerator(rng_type = 'system')
|
||||
|
||||
Previously ``rng``
|
||||
|
||||
Type 'user' also allowed (userspace HMAC_DRBG seeded from system
|
||||
rng). The system RNG is very cheap to create, as just a single file
|
||||
handle or CSP handle is kept open, from first use until shutdown,
|
||||
no matter how many 'system' rng instances are created. Thus it is
|
||||
easy to use the RNG in a one-off way, with `botan.RandomNumberGenerator().get(32)`.
|
||||
|
||||
.. py:method:: get(length)
|
||||
|
||||
Return some bytes
|
||||
|
||||
.. py:method:: reseed(bits = 256)
|
||||
|
||||
Meaningless on system RNG, on userspace RNG causes a reseed/rekey
|
||||
|
||||
.. py:method:: reseed_from_rng(source_rng, bits = 256)
|
||||
|
||||
Take bits from the source RNG and use it to seed ``self``
|
||||
|
||||
.. py:method:: add_entropy(seed)
|
||||
|
||||
Add some unpredictable seed data to the RNG
|
||||
|
||||
Hash Functions
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: HashFunction(algo)
|
||||
|
||||
Previously ``hash_function``
|
||||
|
||||
The ``algo`` param is a string (eg 'SHA-1', 'SHA-384', 'BLAKE2b')
|
||||
|
||||
.. py:method:: algo_name()
|
||||
|
||||
Returns the name of this algorithm
|
||||
|
||||
.. py:method:: clear()
|
||||
|
||||
Clear state
|
||||
|
||||
.. py:method:: output_length()
|
||||
|
||||
Return output length in bytes
|
||||
|
||||
.. py:method:: update(x)
|
||||
|
||||
Add some input
|
||||
|
||||
.. py:method:: final()
|
||||
|
||||
Returns the hash of all input provided, resets
|
||||
for another message.
|
||||
|
||||
Message Authentication Codes
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: MsgAuthCode(algo)
|
||||
|
||||
Previously ``message_authentication_code``
|
||||
|
||||
Algo is a string (eg 'HMAC(SHA-256)', 'Poly1305', 'CMAC(AES-256)')
|
||||
|
||||
.. py:method:: algo_name()
|
||||
|
||||
Returns the name of this algorithm
|
||||
|
||||
.. py:method:: clear()
|
||||
|
||||
Clear internal state including the key
|
||||
|
||||
.. py:method:: output_length()
|
||||
|
||||
Return the output length in bytes
|
||||
|
||||
.. py:method:: set_key(key)
|
||||
|
||||
Set the key
|
||||
|
||||
.. py:method:: update(x)
|
||||
|
||||
Add some input
|
||||
|
||||
.. py:method:: final()
|
||||
|
||||
Returns the MAC of all input provided, resets
|
||||
for another message with the same key.
|
||||
|
||||
Ciphers
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: SymmetricCipher(object, algo, encrypt = True)
|
||||
|
||||
Previously ``cipher``
|
||||
|
||||
The algorithm is spcified as a string (eg 'AES-128/GCM',
|
||||
'Serpent/OCB(12)', 'Threefish-512/EAX').
|
||||
|
||||
Set the second param to False for decryption
|
||||
|
||||
.. py:method:: algo_name()
|
||||
|
||||
Returns the name of this algorithm
|
||||
|
||||
.. py:method:: tag_length()
|
||||
|
||||
Returns the tag length (0 for unauthenticated modes)
|
||||
|
||||
.. py:method:: default_nonce_length()
|
||||
|
||||
Returns default nonce length
|
||||
|
||||
.. py:method:: update_granularity()
|
||||
|
||||
Returns update block size. Call to update() must provide input
|
||||
of exactly this many bytes
|
||||
|
||||
.. py:method:: is_authenticated()
|
||||
|
||||
Returns True if this is an AEAD mode
|
||||
|
||||
.. py:method:: valid_nonce_length(nonce_len)
|
||||
|
||||
Returns True if nonce_len is a valid nonce len for this mode
|
||||
|
||||
.. py:method:: clear()
|
||||
|
||||
Resets all state
|
||||
|
||||
.. py:method:: set_key(key)
|
||||
|
||||
Set the key
|
||||
|
||||
.. py:method:: set_assoc_data(ad)
|
||||
|
||||
Sets the associated data. Fails if this is not an AEAD mode
|
||||
|
||||
.. py:method:: start(nonce)
|
||||
|
||||
Start processing a message using nonce
|
||||
|
||||
.. py:method:: update(txt)
|
||||
|
||||
Consumes input text and returns output. Input text must be of
|
||||
update_granularity() length. Alternately, always call finish
|
||||
with the entire message, avoiding calls to update entirely
|
||||
|
||||
.. py:method:: finish(txt = None)
|
||||
|
||||
Finish processing (with an optional final input). May throw if
|
||||
message authentication checks fail, in which case all plaintext
|
||||
previously processed must be discarded. You may call finish()
|
||||
with the entire message
|
||||
|
||||
Bcrypt
|
||||
----------------------------------------
|
||||
|
||||
.. py:function:: bcrypt(passwd, rng, work_factor = 10)
|
||||
|
||||
Provided the password and an RNG object, returns a bcrypt string
|
||||
|
||||
.. py:function:: check_bcrypt(passwd, bcrypt)
|
||||
|
||||
Check a bcrypt hash against the provided password, returning True
|
||||
iff the password matches.
|
||||
|
||||
PBKDF
|
||||
----------------------------------------
|
||||
|
||||
.. py:function:: pbkdf(algo, password, out_len, iterations = 100000, salt = None)
|
||||
|
||||
Runs a PBKDF2 algo specified as a string (eg 'PBKDF2(SHA-256)',
|
||||
'PBKDF2(CMAC(Blowfish))'). Runs with specified iterations, with
|
||||
meaning depending on the algorithm. The salt can be provided or
|
||||
otherwise is randomly chosen. In any case it is returned from the
|
||||
call.
|
||||
|
||||
Returns out_len bytes of output (or potentially less depending on
|
||||
the algorithm and the size of the request).
|
||||
|
||||
Returns tuple of salt, iterations, and psk
|
||||
|
||||
.. py:function:: pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12))
|
||||
|
||||
Runs for as many iterations as needed to consumed ms_to_run
|
||||
milliseconds on whatever we're running on. Returns tuple of salt,
|
||||
iterations, and psk
|
||||
|
||||
Scrypt
|
||||
---------------
|
||||
|
||||
.. versionadded:: 2.8.0
|
||||
|
||||
.. py:function:: scrypt(out_len, password, salt, N=1024, r=8, p=8)
|
||||
|
||||
Runs Scrypt key derivation function over the specified password
|
||||
and salt using Scrypt parameters N, r, p.
|
||||
|
||||
KDF
|
||||
----------------------------------------
|
||||
|
||||
.. py:function:: kdf(algo, secret, out_len, salt)
|
||||
|
||||
Performs a key derviation function (such as "HKDF(SHA-384)") over
|
||||
the provided secret and salt values. Returns a value of the
|
||||
specified length.
|
||||
|
||||
Public Key
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: PublicKey(object)
|
||||
|
||||
Previously ``public_key``
|
||||
|
||||
.. py:classmethod:: load(val)
|
||||
|
||||
Load a public key. The value should be a PEM or DER blob.
|
||||
|
||||
.. py:classmethod:: load_rsa(n, e)
|
||||
|
||||
Load an RSA public key giving the modulus and public exponent
|
||||
as integers.
|
||||
|
||||
.. py:classmethod:: load_dsa(p, q, g, y)
|
||||
|
||||
Load an DSA public key giving the parameters and public value
|
||||
as integers.
|
||||
|
||||
.. py:classmethod:: load_dh(p, g, y)
|
||||
|
||||
Load an Diffie-Hellman public key giving the parameters and
|
||||
public value as integers.
|
||||
|
||||
.. py:classmethod:: load_elgamal(p, q, g, y)
|
||||
|
||||
Load an ElGamal public key giving the parameters and
|
||||
public value as integers.
|
||||
|
||||
.. py:classmethod:: load_ecdsa(curve, pub_x, pub_y)
|
||||
|
||||
Load an ECDSA public key giving the curve as a string
|
||||
(like "secp256r1") and the public point as a pair of
|
||||
integers giving the affine coordinates.
|
||||
|
||||
.. py:classmethod:: load_ecdh(curve, pub_x, pub_y)
|
||||
|
||||
Load an ECDH public key giving the curve as a string
|
||||
(like "secp256r1") and the public point as a pair of
|
||||
integers giving the affine coordinates.
|
||||
|
||||
.. py:classmethod:: load_sm2(curve, pub_x, pub_y)
|
||||
|
||||
Load a SM2 public key giving the curve as a string (like
|
||||
"sm2p256v1") and the public point as a pair of integers giving
|
||||
the affine coordinates.
|
||||
|
||||
.. py:method:: check_key(rng_obj, strong=True):
|
||||
|
||||
Test the key for consistency. If ``strong`` is ``True`` then
|
||||
more expensive tests are performed.
|
||||
|
||||
.. py:method:: export(pem=False)
|
||||
|
||||
Exports the public key using the usual X.509 SPKI representation.
|
||||
If ``pem`` is True, the result is a PEM encoded string. Otherwise
|
||||
it is a binary DER value.
|
||||
|
||||
.. py:method:: to_der()
|
||||
|
||||
Like ``self.export(False)``
|
||||
|
||||
.. py:method:: to_pem()
|
||||
|
||||
Like ``self.export(True)``
|
||||
|
||||
.. py:method:: get_field(field_name)
|
||||
|
||||
Return an integer field related to the public key. The valid field names
|
||||
vary depending on the algorithm. For example RSA public modulus can be
|
||||
extracted with ``rsa_key.get_field("n")``.
|
||||
|
||||
.. py:method:: fingerprint(hash = 'SHA-256')
|
||||
|
||||
Returns a hash of the public key
|
||||
|
||||
.. py:method:: algo_name()
|
||||
|
||||
Returns the algorithm name
|
||||
|
||||
.. py:method:: estimated_strength()
|
||||
|
||||
Returns the estimated strength of this key against known attacks
|
||||
(NFS, Pollard's rho, etc)
|
||||
|
||||
Private Key
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: PrivateKey
|
||||
|
||||
Previously ``private_key``
|
||||
|
||||
.. py:classmethod:: create(algo, param, rng)
|
||||
|
||||
Creates a new private key. The parameter type/value depends on
|
||||
the algorithm. For "rsa" is is the size of the key in bits.
|
||||
For "ecdsa" and "ecdh" it is a group name (for instance
|
||||
"secp256r1"). For "ecdh" there is also a special case for group
|
||||
"curve25519" (which is actually a completely distinct key type
|
||||
with a non-standard encoding).
|
||||
|
||||
.. py:classmethod:: load(val, passphrase="")
|
||||
|
||||
Return a private key (DER or PEM formats accepted)
|
||||
|
||||
.. py:classmethod:: load_rsa(p, q, e)
|
||||
|
||||
Return a private RSA key
|
||||
|
||||
.. py:classmethod:: load_dsa(p, q, g, x)
|
||||
|
||||
Return a private DSA key
|
||||
|
||||
.. py:classmethod:: load_dh(p, g, x)
|
||||
|
||||
Return a private DH key
|
||||
|
||||
.. py:classmethod:: load_elgamal(p, q, g, x)
|
||||
|
||||
Return a private ElGamal key
|
||||
|
||||
.. py:classmethod:: load_ecdsa(curve, x)
|
||||
|
||||
Return a private ECDSA key
|
||||
|
||||
.. py:classmethod:: load_ecdh(curve, x)
|
||||
|
||||
Return a private ECDH key
|
||||
|
||||
.. py:classmethod:: load_sm2(curve, x)
|
||||
|
||||
Return a private SM2 key
|
||||
|
||||
.. py:method:: get_public_key()
|
||||
|
||||
Return a public_key object
|
||||
|
||||
.. py:method:: to_pem()
|
||||
|
||||
Return the PEM encoded private key (unencrypted). Like ``self.export(True)``
|
||||
|
||||
.. py:method:: to_der()
|
||||
|
||||
Return the PEM encoded private key (unencrypted). Like ``self.export(False)``
|
||||
|
||||
.. py:method:: check_key(rng_obj, strong=True):
|
||||
|
||||
Test the key for consistency. If ``strong`` is ``True`` then
|
||||
more expensive tests are performed.
|
||||
|
||||
.. py:method:: algo_name()
|
||||
|
||||
Returns the algorithm name
|
||||
|
||||
.. py:method:: export(pem=False)
|
||||
|
||||
Exports the private key in PKCS8 format. If ``pem`` is True, the
|
||||
result is a PEM encoded string. Otherwise it is a binary DER
|
||||
value. The key will not be encrypted.
|
||||
|
||||
.. py:method:: export_encrypted(passphrase, rng, pem=False, msec=300, cipher=None, pbkdf=None)
|
||||
|
||||
Exports the private key in PKCS8 format, encrypted using the
|
||||
provided passphrase. If ``pem`` is True, the result is a PEM
|
||||
encoded string. Otherwise it is a binary DER value.
|
||||
|
||||
.. py:method:: get_field(field_name)
|
||||
|
||||
Return an integer field related to the public key. The valid field names
|
||||
vary depending on the algorithm. For example first RSA secret prime can be
|
||||
extracted with ``rsa_key.get_field("p")``. This function can also be
|
||||
used to extract the public parameters.
|
||||
|
||||
Public Key Operations
|
||||
----------------------------------------
|
||||
|
||||
.. py:class:: PKEncrypt(pubkey, padding)
|
||||
|
||||
Previously ``pk_op_encrypt``
|
||||
|
||||
.. py:method:: encrypt(msg, rng)
|
||||
|
||||
.. py:class:: PKDecrypt(privkey, padding)
|
||||
|
||||
Previously ``pk_op_decrypt``
|
||||
|
||||
.. py:method:: decrypt(msg)
|
||||
|
||||
.. py:class:: PKSign(privkey, hash_w_padding)
|
||||
|
||||
Previously ``pk_op_sign``
|
||||
|
||||
.. py:method:: update(msg)
|
||||
.. py:method:: finish(rng)
|
||||
|
||||
.. py:class:: PKVerify(pubkey, hash_w_padding)
|
||||
|
||||
Previously ``pk_op_verify``
|
||||
|
||||
.. py:method:: update(msg)
|
||||
.. py:method:: check_signature(signature)
|
||||
|
||||
.. py:class:: PKKeyAgreement(privkey, kdf)
|
||||
|
||||
Previously ``pk_op_key_agreement``
|
||||
|
||||
.. py:method:: public_value()
|
||||
|
||||
Returns the public value to be passed to the other party
|
||||
|
||||
.. py:method:: agree(other, key_len, salt)
|
||||
|
||||
Returns a key derived by the KDF.
|
||||
|
||||
Multiple Precision Integers (MPI)
|
||||
-------------------------------------
|
||||
.. versionadded:: 2.8.0
|
||||
|
||||
.. py:class:: MPI(initial_value=None, radix=None)
|
||||
|
||||
Initialize an MPI object with specified value, left as zero otherwise. The
|
||||
``initial_value`` should be an ``int``, ``str``, or ``MPI``.
|
||||
The ``radix`` value should be set to 16 when initializing from a base 16 `str` value.
|
||||
|
||||
|
||||
Most of the usual arithmetic operators (``__add__``, ``__mul__``, etc) are
|
||||
defined.
|
||||
|
||||
.. py:method:: inverse_mod(modulus)
|
||||
|
||||
Return the inverse of ``self`` modulo ``modulus``, or zero if no inverse exists
|
||||
|
||||
.. py:method:: is_prime(rng, prob=128)
|
||||
|
||||
Test if ``self`` is prime
|
||||
|
||||
.. py:method:: pow_mod(exponent, modulus):
|
||||
|
||||
Return ``self`` to the ``exponent`` power modulo ``modulus``
|
||||
|
||||
.. py:method:: mod_mul(other, modulus):
|
||||
|
||||
Return the multiplication product of ``self`` and ``other`` modulo ``modulus``
|
||||
|
||||
.. py:method:: gcd(other):
|
||||
|
||||
Return the greatest common divisor of ``self`` and ``other``
|
||||
|
||||
|
||||
Format Preserving Encryption (FE1 scheme)
|
||||
-----------------------------------------
|
||||
.. versionadded:: 2.8.0
|
||||
|
||||
.. py:class:: FormatPreservingEncryptionFE1(modulus, key, rounds=5, compat_mode=False)
|
||||
|
||||
Initialize an instance for format preserving encryption
|
||||
|
||||
.. py:method:: encrypt(msg, tweak)
|
||||
|
||||
The msg should be a botan3.MPI or an object which can be converted to one
|
||||
|
||||
.. py:method:: decrypt(msg, tweak)
|
||||
|
||||
The msg should be a botan3.MPI or an object which can be converted to one
|
||||
|
||||
HOTP
|
||||
-----------------------------------------
|
||||
.. versionadded:: 2.8.0
|
||||
|
||||
.. py:class:: HOTP(key, hash="SHA-1", digits=6)
|
||||
|
||||
.. py:method:: generate(counter)
|
||||
|
||||
Generate an HOTP code for the provided counter
|
||||
|
||||
.. py:method:: check(code, counter, resync_range=0)
|
||||
|
||||
Check if provided ``code`` is the correct code for ``counter``.
|
||||
If ``resync_range`` is greater than zero, HOTP also checks
|
||||
up to ``resync_range`` following counter values.
|
||||
|
||||
Returns a tuple of (bool,int) where the boolean indicates if the
|
||||
code was valid, and the int indicates the next counter value
|
||||
that should be used. If the code did not verify, the next
|
||||
counter value is always identical to the counter that was passed
|
||||
in. If the code did verify and resync_range was zero, then the
|
||||
next counter will always be counter+1.
|
||||
|
||||
X509Cert
|
||||
-----------------------------------------
|
||||
|
||||
.. py:class:: X509Cert(filename=None, buf=None)
|
||||
|
||||
.. py:method:: time_starts()
|
||||
|
||||
Return the time the certificate becomes valid, as a string in form
|
||||
"YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is
|
||||
relative to UTC.
|
||||
|
||||
.. py:method:: time_expires()
|
||||
|
||||
Return the time the certificate expires, as a string in form
|
||||
"YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is
|
||||
relative to UTC.
|
||||
|
||||
.. py:method:: to_string()
|
||||
|
||||
Format the certificate as a free-form string.
|
||||
|
||||
.. py:method:: fingerprint(hash_algo='SHA-256')
|
||||
|
||||
Return a fingerprint for the certificate, which is basically just a hash
|
||||
of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash
|
||||
function is allowed.
|
||||
|
||||
.. py:method:: serial_number()
|
||||
|
||||
Return the serial number of the certificate.
|
||||
|
||||
.. py:method:: authority_key_id()
|
||||
|
||||
Return the authority key ID set in the certificate, which may be empty.
|
||||
|
||||
.. py:method:: subject_key_id()
|
||||
|
||||
Return the subject key ID set in the certificate, which may be empty.
|
||||
|
||||
.. py:method:: subject_public_key_bits()
|
||||
|
||||
Get the serialized representation of the public key included in this certificate.
|
||||
|
||||
.. py:method:: subject_public_key()
|
||||
|
||||
Get the public key included in this certificate as an object of class ``PublicKey``.
|
||||
|
||||
.. py:method:: subject_dn(key, index)
|
||||
|
||||
Get a value from the subject DN field.
|
||||
|
||||
``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`.
|
||||
|
||||
.. py:method:: issuer_dn(key, index)
|
||||
|
||||
Get a value from the issuer DN field.
|
||||
|
||||
``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`.
|
||||
|
||||
.. py:method:: hostname_match(hostname)
|
||||
|
||||
Return True if the Common Name (CN) field of the certificate matches a given ``hostname``.
|
||||
|
||||
.. py:method:: not_before()
|
||||
|
||||
Return the time the certificate becomes valid, as seconds since epoch.
|
||||
|
||||
.. py:method:: not_after()
|
||||
|
||||
Return the time the certificate expires, as seconds since epoch.
|
||||
|
||||
.. py:method:: allowed_usage(usage_list)
|
||||
|
||||
Return True if the certificates Key Usage extension contains all constraints given in ``usage_list``.
|
||||
Also return True if the certificate doesn't have this extension.
|
||||
Example usage constraints are: ``"DIGITAL_SIGNATURE"``, ``"KEY_CERT_SIGN"``, ``"CRL_SIGN"``.
|
||||
|
||||
.. py:method:: verify(intermediates=None, \
|
||||
trusted=None, \
|
||||
trusted_path=None, \
|
||||
required_strength=0, \
|
||||
hostname=None, \
|
||||
reference_time=0 \
|
||||
crls=None)
|
||||
|
||||
Verify a certificate. Returns 0 if validation was successful, returns a positive error code
|
||||
if the validation was unsuccesful.
|
||||
|
||||
``intermediates`` is a list of untrusted subauthorities.
|
||||
|
||||
``trusted`` is a list of trusted root CAs.
|
||||
|
||||
The `trusted_path` refers to a directory where one or more trusted CA
|
||||
certificates are stored.
|
||||
|
||||
Set ``required_strength`` to indicate the minimum key and hash strength
|
||||
that is allowed. For instance setting to 80 allows 1024-bit RSA and SHA-1.
|
||||
Setting to 110 requires 2048-bit RSA and SHA-256 or higher. Set to zero
|
||||
to accept a default.
|
||||
|
||||
If ``hostname`` is given, it will be checked against the certificates CN field.
|
||||
|
||||
Set ``reference_time`` to be the time which the certificate chain is
|
||||
validated against. Use zero (default) to use the current system clock.
|
||||
|
||||
``crls`` is a list of CRLs issued by either trusted or untrusted authorities.
|
||||
|
||||
.. py:classmethod:: validation_status(error_code)
|
||||
|
||||
Return an informative string associated with the verification return code.
|
||||
|
||||
.. py:method:: is_revoked(self, crl)
|
||||
|
||||
Check if the certificate (``self``) is revoked on the given ``crl``.
|
||||
|
||||
X509CRL
|
||||
-----------------------------------------
|
||||
|
||||
.. py:class:: X509CRL(filename=None, buf=None)
|
||||
|
||||
Class representing an X.509 Certificate Revocation List.
|
||||
|
||||
A CRL in PEM or DER format can be loaded from a file, with the ``filename`` argument,
|
||||
or from a bytestring, with the ``buf`` argument.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,289 +0,0 @@
|
||||
.. _random_number_generators:
|
||||
|
||||
Random Number Generators
|
||||
========================================
|
||||
|
||||
.. cpp:class:: RandomNumberGenerator
|
||||
|
||||
The base class for all RNG objects, is declared in ``rng.h``.
|
||||
|
||||
.. cpp:function:: void randomize(uint8_t* output_array, size_t length)
|
||||
|
||||
Places *length* random bytes into the provided buffer.
|
||||
|
||||
.. cpp:function:: void randomize_with_input(uint8_t* data, size_t length, \
|
||||
const uint8_t* extra_input, size_t extra_input_len)
|
||||
|
||||
Like randomize, but first incorporates the additional input field into the
|
||||
state of the RNG. The additional input could be anything which
|
||||
parameterizes this request. Not all RNG types accept additional inputs,
|
||||
the value will be silently ignored when not supported.
|
||||
|
||||
.. cpp:function:: void randomize_with_ts_input(uint8_t* data, size_t length)
|
||||
|
||||
Creates a buffer with some timestamp values and calls ``randomize_with_input``
|
||||
|
||||
.. note::
|
||||
|
||||
When RDRAND is enabled and available at runtime, instead of timestamps
|
||||
the output of RDRAND is used as the additional data.
|
||||
|
||||
.. cpp:function:: uint8_t next_byte()
|
||||
|
||||
Generates a single random byte and returns it. Note that calling this
|
||||
function several times is much slower than calling ``randomize`` once to
|
||||
produce multiple bytes at a time.
|
||||
|
||||
.. cpp:function:: void add_entropy(const uint8_t* data, size_t length)
|
||||
|
||||
Incorporates provided data into the state of the PRNG, if at all possible.
|
||||
This works for most RNG types, including the system and TPM RNGs. But if
|
||||
the RNG doesn't support this operation, the data is dropped, no error is
|
||||
indicated.
|
||||
|
||||
.. cpp:function:: bool accepts_input() const
|
||||
|
||||
This function returns ``false`` if it is known that this RNG object cannot
|
||||
accept external inputs. In this case, any calls to
|
||||
:cpp:func:`RandomNumberGenerator::add_entropy` will be ignored.
|
||||
|
||||
.. cpp:function:: void reseed_from_rng(RandomNumberGenerator& rng, \
|
||||
size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS)
|
||||
|
||||
Reseed by calling ``rng`` to acquire ``poll_bits`` data.
|
||||
|
||||
|
||||
RNG Types
|
||||
----------------------------------------
|
||||
|
||||
Several different RNG types are implemented. Some access hardware RNGs, which
|
||||
are only available on certain platforms. Others are mostly useful in specific
|
||||
situations.
|
||||
|
||||
Generally prefer using ``System_RNG``, or if not available use ``AutoSeeded_RNG``
|
||||
which is intended to provide best possible behavior in a userspace PRNG.
|
||||
|
||||
System_RNG
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On systems which support it, in ``system_rng.h`` you can access a shared
|
||||
reference to a process global instance of the system PRNG (using interfaces such
|
||||
as ``/dev/urandom``, ``getrandom``, ``arc4random``, ``BCryptGenRandom``,
|
||||
or ``RtlGenRandom``):
|
||||
|
||||
.. cpp:function:: RandomNumberGenerator& system_rng()
|
||||
|
||||
Returns a reference to the system RNG
|
||||
|
||||
There is also a wrapper class ``System_RNG`` which simply invokes on
|
||||
the return value of ``system_rng()``. This is useful in situations where
|
||||
you may sometimes want to use the system RNG and a userspace RNG in others,
|
||||
for example::
|
||||
|
||||
std::unique_ptr<Botan::RandomNumberGenerator> rng;
|
||||
#if defined(BOTAN_HAS_SYSTEM_RNG)
|
||||
rng.reset(new System_RNG);
|
||||
#else
|
||||
rng.reset(new AutoSeeded_RNG);
|
||||
#endif
|
||||
|
||||
Unlike nearly any other object in Botan it is acceptable to share a single
|
||||
instance of ``System_RNG`` between threads without locking, because the underlying
|
||||
RNG is itself thread safe due to being serialized by a mutex in the kernel itself.
|
||||
|
||||
AutoSeeded_RNG
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
AutoSeeded_RNG is type naming a 'best available' userspace PRNG. The
|
||||
exact definition of this has changed over time and may change again in the
|
||||
future. Fortunately there is no compatibility concerns when changing
|
||||
any RNG since the only expectation is it produces bits
|
||||
indistinguishable from random.
|
||||
|
||||
.. note:: Starting in 2.16.0, AutoSeeded_RNG uses an internal lock and so is
|
||||
safe to share among threads. However if possible it is still better to
|
||||
use a RNG per thread as otherwise the RNG object needlessly creates a
|
||||
point of contention. In previous versions, the RNG does not have an
|
||||
internal lock and all access to it must be serialized.
|
||||
|
||||
The current version uses HMAC_DRBG with either SHA-384 or SHA-256. The
|
||||
initial seed is generated either by the system PRNG (if available) or
|
||||
a default set of entropy sources. These are also used for periodic
|
||||
reseeding of the RNG state.
|
||||
|
||||
HMAC_DRBG
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
HMAC-DRBG is a random number generator designed by NIST and specified
|
||||
in SP 800-90A. It seems to be the most conservative generator of the
|
||||
NIST approved options.
|
||||
|
||||
It can be instantiated with any HMAC but is typically used with
|
||||
SHA-256, SHA-384, or SHA-512, as these are the hash functions approved
|
||||
for this use by NIST.
|
||||
|
||||
.. note::
|
||||
There is no reason to use this class directly unless your application
|
||||
requires HMAC-DRBG with specific parameters or options. Usually this
|
||||
would be for some standards conformance reason. If you just want a
|
||||
userspace RNG, use ``AutoSeeded_RNG``.
|
||||
|
||||
``HMAC_DRBG``'s constructors are:
|
||||
|
||||
.. cpp:class:: HMAC_DRBG
|
||||
|
||||
.. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \
|
||||
RandomNumberGenerator& underlying_rng, \
|
||||
size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \
|
||||
size_t max_number_of_bytes_per_request = 64 * 1024)
|
||||
|
||||
Creates a DRBG which will automatically reseed as required by making
|
||||
calls to ``underlying_rng`` either after being invoked
|
||||
``reseed_interval`` times, or if use of ``fork`` system call is
|
||||
detected.
|
||||
|
||||
You can disable automatic reseeding by setting ``reseed_interval`` to
|
||||
zero, in which case ``underlying_rng`` will only be invoked in the case
|
||||
of ``fork``.
|
||||
|
||||
The specification of HMAC DRBG requires that each invocation produce no
|
||||
more than 64 kibibytes of data. However, the RNG interface allows
|
||||
producing arbitrary amounts of data in a single request. To accommodate
|
||||
this, ``HMAC_DRBG`` treats requests for more data as if they were
|
||||
multiple requests each of (at most) the maximum size. You can specify a
|
||||
smaller maximum size with ``max_number_of_bytes_per_request``. There is
|
||||
normally no reason to do this.
|
||||
|
||||
.. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \
|
||||
Entropy_Sources& entropy_sources, \
|
||||
size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \
|
||||
size_t max_number_of_bytes_per_request = 64 * 1024)
|
||||
|
||||
Like above function, but instead of an RNG taking a set of entropy
|
||||
sources to seed from as required.
|
||||
|
||||
.. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \
|
||||
RandomNumberGenerator& underlying_rng, \
|
||||
Entropy_Sources& entropy_sources, \
|
||||
size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \
|
||||
size_t max_number_of_bytes_per_request = 64 * 1024)
|
||||
|
||||
Like above function, but taking both an RNG and a set of entropy
|
||||
sources to seed from as required.
|
||||
|
||||
.. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf)
|
||||
|
||||
Creates an unseeded DRBG. You must explicitly provide seed data later
|
||||
on in order to use this RNG. This is primarily useful for deterministic
|
||||
key generation.
|
||||
|
||||
Since no source of data is available to automatically reseed, automatic
|
||||
reseeding is disabled when this constructor is used. If the RNG object
|
||||
detects that ``fork`` system call was used without it being
|
||||
subsequently reseeded, it will throw an exception.
|
||||
|
||||
.. cpp:function:: HMAC_DRBG(const std::string& hmac_hash)
|
||||
|
||||
Like the constructor just taking a PRF, except instead of a PRF object,
|
||||
a string specifying what hash to use with HMAC is provided.
|
||||
|
||||
ChaCha_RNG
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a very fast userspace PRNG based on ChaCha20 and HMAC(SHA-256). The key
|
||||
for ChaCha is derived by hashing entropy inputs with HMAC. Then the ChaCha
|
||||
keystream generator is run, first to generate the new HMAC key (used for any
|
||||
future entropy additions), then the desired RNG outputs.
|
||||
|
||||
This RNG composes two primitives thought to be secure (ChaCha and HMAC) in a
|
||||
simple and well studied way (the extract-then-expand paradigm), but is still an
|
||||
ad-hoc and non-standard construction. It is included because it is roughly 20x
|
||||
faster then HMAC_DRBG (basically running as fast as ChaCha can generate
|
||||
keystream bits), and certain applications need access to a very fast RNG.
|
||||
|
||||
One thing applications using ``ChaCha_RNG`` need to be aware of is that for
|
||||
performance reasons, no backtracking resistance is implemented in the RNG
|
||||
design. An attacker who recovers the ``ChaCha_RNG`` state can recover the output
|
||||
backwards in time to the last rekey and forwards to the next rekey.
|
||||
|
||||
An explicit reseeding (:cpp:func:`RandomNumberGenerator::add_entropy`) or
|
||||
providing any input to the RNG
|
||||
(:cpp:func:`RandomNumberGenerator::randomize_with_ts_input`,
|
||||
:cpp:func:`RandomNumberGenerator::randomize_with_input`) is sufficient to cause
|
||||
a reseeding. Or, if a RNG or entropy source was provided to the ``ChaCha_RNG``
|
||||
constructor, then reseeding will be performed automatically after a certain
|
||||
interval of requests.
|
||||
|
||||
Processor_RNG
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
This RNG type directly invokes a CPU instruction capable of generating
|
||||
a cryptographically secure random number. On x86 it uses ``rdrand``,
|
||||
on POWER ``darn``. If the relevant instruction is not available, the
|
||||
constructor of the class will throw at runtime. You can test
|
||||
beforehand by checking the result of ``Processor_RNG::available()``.
|
||||
|
||||
TPM_RNG
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
This RNG type allows using the RNG exported from a TPM chip.
|
||||
|
||||
PKCS11_RNG
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
This RNG type allows using the RNG exported from a hardware token accessed via PKCS11.
|
||||
|
||||
Entropy Sources
|
||||
---------------------------------
|
||||
|
||||
An ``EntropySource`` is an abstract representation of some method of
|
||||
gather "real" entropy. This tends to be very system dependent. The
|
||||
*only* way you should use an ``EntropySource`` is to pass it to a PRNG
|
||||
that will extract entropy from it -- never use the output directly for
|
||||
any kind of key or nonce generation!
|
||||
|
||||
``EntropySource`` has a pair of functions for getting entropy from
|
||||
some external source, called ``fast_poll`` and ``slow_poll``. These
|
||||
pass a buffer of bytes to be written; the functions then return how
|
||||
many bytes of entropy were gathered.
|
||||
|
||||
Note for writers of ``EntropySource`` subclasses: it isn't necessary
|
||||
to use any kind of cryptographic hash on your output. The data
|
||||
produced by an EntropySource is only used by an application after it
|
||||
has been hashed by the ``RandomNumberGenerator`` that asked for the
|
||||
entropy, thus any hashing you do will be wasteful of both CPU cycles
|
||||
and entropy.
|
||||
|
||||
The following entropy sources are currently used:
|
||||
|
||||
* The system RNG (``/dev/urandom``, ``getrandom``, ``arc4random``,
|
||||
``BCryptGenRandom``, or ``RtlGenRandom``).
|
||||
* Processor provided RNG outputs (RDRAND, RDSEED, DARN) are used if available,
|
||||
but not counted as contributing entropy
|
||||
* The ``getentropy`` call is used on OpenBSD, FreeBSD, and macOS
|
||||
* ``/proc`` walk: read files in ``/proc``. Last ditch protection against
|
||||
flawed system RNG.
|
||||
* Win32 stats: takes snapshot of current system processes. Last ditch
|
||||
protection against flawed system RNG.
|
||||
|
||||
Fork Safety
|
||||
---------------------------------
|
||||
|
||||
On Unix platforms, the ``fork()`` and ``clone()`` system calls can
|
||||
be used to spawn a new child process. Fork safety ensures that the
|
||||
child process doesn't see the same output of random bytes as the
|
||||
parent process. Botan tries to ensure fork safety by feeding the
|
||||
process ID into the internal state of the random generator and by
|
||||
automatically reseeding the random generator if the process ID
|
||||
changed between two requests of random bytes. However, this does
|
||||
not protect against PID wrap around. The process ID is usually
|
||||
implemented as a 16 bit integer. In this scenario, a process will
|
||||
spawn a new child process, which exits the parent process and
|
||||
spawns a new child process himself. If the PID wrapped around, the
|
||||
second child process may get assigned the process ID of it's
|
||||
grandparent and the fork safety can not be ensured.
|
||||
|
||||
Therefore, it is strongly recommended to explicitly reseed any
|
||||
userspace random generators after forking a new process. If this is
|
||||
not possible in your application, prefer using the system PRNG
|
||||
instead.
|
@ -1,6 +0,0 @@
|
||||
Roughtime
|
||||
===========
|
||||
|
||||
.. versionadded:: 2.13.0
|
||||
|
||||
Botan includes a Roughtime client, available in ``botan/roughtime.h``
|
@ -1,31 +0,0 @@
|
||||
|
||||
Memory container
|
||||
========================================
|
||||
|
||||
A major concern with mixing modern multi-user OSes and cryptographic
|
||||
code is that at any time the code (including secret keys) could be
|
||||
swapped to disk, where it can later be read by an attacker, or left
|
||||
floating around in memory for later retrieval.
|
||||
|
||||
For this reason the library uses a ``std::vector`` with a custom
|
||||
allocator that will zero memory before deallocation, named via typedef
|
||||
as ``secure_vector``. Because it is simply a STL vector with a custom
|
||||
allocator, it has an identical API to the ``std::vector`` you know and
|
||||
love.
|
||||
|
||||
Some operating systems offer the ability to lock memory into RAM,
|
||||
preventing swapping from occurring. Typically this operation is
|
||||
restricted to privileged users (root or admin), however some OSes
|
||||
including Linux and FreeBSD allow normal users to lock a small amount
|
||||
of memory. On these systems, allocations first attempt to allocate out
|
||||
of this small locked pool, and then if that fails will fall back to
|
||||
normal heap allocations.
|
||||
|
||||
The ``secure_vector`` template is only meant for primitive data types
|
||||
(bytes or ints): if you want a container of higher level Botan
|
||||
objects, you can just use a ``std::vector``, since these objects know
|
||||
how to clear themselves when they are destroyed. You cannot, however,
|
||||
have a ``std::vector`` (or any other container) of ``Pipe`` objects or
|
||||
filters, because these types have pointers to other filters, and
|
||||
implementing copy constructors for these types would be both hard and
|
||||
quite expensive (vectors of pointers to such objects is fine, though).
|
@ -1,77 +0,0 @@
|
||||
Secure Remote Password
|
||||
========================================
|
||||
|
||||
The library contains an implementation of the
|
||||
`SRP6-a <http://srp.stanford.edu/design.html>`_ password authenticated
|
||||
key exchange protocol in ``srp6.h``.
|
||||
|
||||
A SRP client provides what is called a SRP *verifier* to the server.
|
||||
This verifier is based on a password, but the password cannot be
|
||||
easily derived from the verifier (however brute force attacks are
|
||||
possible). Later, the client and server can perform an SRP exchange,
|
||||
which results in a shared secret key. This key can be used for mutual
|
||||
authentication and/or encryption.
|
||||
|
||||
SRP works in a discrete logarithm group. Special parameter sets for
|
||||
SRP6 are defined, denoted in the library as "modp/srp/<size>", for
|
||||
example "modp/srp/2048".
|
||||
|
||||
.. warning::
|
||||
|
||||
While knowledge of the verifier does not easily allow an attacker
|
||||
to get the raw password, they could still use the verifier to
|
||||
impersonate the server to the client, so verifiers should be
|
||||
protected as carefully as a plaintext password would be.
|
||||
|
||||
.. cpp:function:: BigInt generate_srp6_verifier( \
|
||||
const std::string& username, \
|
||||
const std::string& password, \
|
||||
const std::vector<uint8_t>& salt, \
|
||||
const std::string& group_id, \
|
||||
const std::string& hash_id)
|
||||
|
||||
Generates a new verifier using the specified password and salt.
|
||||
This is stored by the server. The salt must also be stored. Later,
|
||||
the given username and password are used to by the client during
|
||||
the key agreement step.
|
||||
|
||||
.. cpp:function:: std::string srp6_group_identifier( \
|
||||
const BigInt& N, const BigInt& g)
|
||||
|
||||
.. cpp:class:: SRP6_Server_Session
|
||||
|
||||
.. cpp:function:: BigInt step1(const BigInt& v, \
|
||||
const std::string& group_id, \
|
||||
const std::string& hash_id, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
Takes a verifier (generated by generate_srp6_verifier) along
|
||||
with the group_id, and output a value `B` which is provided to
|
||||
the client.
|
||||
|
||||
.. cpp:function:: SymmetricKey step2(const BigInt& A)
|
||||
|
||||
Takes the parameter A generated by srp6_client_agree,
|
||||
and return the shared secret key.
|
||||
|
||||
In the event of an impersonation attack (or wrong username/password, etc)
|
||||
no error occurs, but the key returned will be different on the two sides.
|
||||
The two sides must verify each other, for example by using the shared
|
||||
secret to key an HMAC and then exchanging authenticated messages.
|
||||
|
||||
.. cpp:function:: std::pair<BigInt,SymmetricKey> srp6_client_agree( \
|
||||
const std::string& username, \
|
||||
const std::string& password, \
|
||||
const std::string& group_id, \
|
||||
const std::string& hash_id, \
|
||||
const std::vector<uint8_t>& salt, \
|
||||
const BigInt& B, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
The client receives these parameters from the server, except for
|
||||
the username and password which are provided by the user. The
|
||||
parameter B is the output of `step1`.
|
||||
|
||||
The client agreement step outputs a shared symmetric key along
|
||||
with the parameter A which is returned to the server (and allows
|
||||
it the compute the shared key).
|
@ -1,194 +0,0 @@
|
||||
Stream Ciphers
|
||||
========================
|
||||
|
||||
In contrast to block ciphers, stream ciphers operate on a plaintext stream
|
||||
instead of blocks. Thus encrypting data results in changing the internal state
|
||||
of the cipher and encryption of plaintext with arbitrary length is possible in
|
||||
one go (in byte amounts). All implemented stream ciphers derive from the base
|
||||
class :cpp:class:`StreamCipher` (`botan/stream_cipher.h`).
|
||||
|
||||
.. warning::
|
||||
|
||||
Using a stream cipher without an authentication code is extremely insecure,
|
||||
because an attacker can trivially modify messages. Prefer using an
|
||||
authenticated cipher mode such as GCM or SIV.
|
||||
|
||||
.. warning::
|
||||
|
||||
Encrypting more than one message with the same key requires careful management
|
||||
of initialization vectors. Otherwise the keystream will be reused, which causes
|
||||
the security of the cipher to completely fail.
|
||||
|
||||
.. cpp:class:: StreamCipher
|
||||
|
||||
.. cpp:function:: std::string name() const
|
||||
|
||||
Returns a human-readable string of the name of this algorithm.
|
||||
|
||||
.. cpp:function:: void clear()
|
||||
|
||||
Clear the key.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<StreamCipher> new_object() const
|
||||
|
||||
Return a newly allocated object of the same type as this one.
|
||||
The new object is unkeyed.
|
||||
|
||||
.. cpp:function:: void set_key(const uint8_t* key, size_t length)
|
||||
|
||||
Set the stream cipher key. If the length is not accepted, an
|
||||
``Invalid_Key_Length`` exception is thrown.
|
||||
|
||||
.. cpp:function:: bool valid_keylength(size_t length) const
|
||||
|
||||
This function returns true if and only if *length* is a valid
|
||||
keylength for the algorithm.
|
||||
|
||||
.. cpp:function:: size_t minimum_keylength() const
|
||||
|
||||
Return the smallest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: size_t maximum_keylength() const
|
||||
|
||||
Return the largest key length (in bytes) that is acceptable for the
|
||||
algorithm.
|
||||
|
||||
.. cpp:function:: bool valid_iv_length(size_t iv_len) const
|
||||
|
||||
This function returns true if and only if *length* is a valid IV length for
|
||||
the stream cipher. Some ciphers do not support IVs at all, and will return
|
||||
false for any value except zero.
|
||||
|
||||
.. cpp:function:: size_t default_iv_length() const
|
||||
|
||||
Returns some default IV size, normally the largest IV supported by the cipher.
|
||||
If this function returns zero, then IVs are not supported and any call to
|
||||
``set_iv`` with a non-empty value will fail.
|
||||
|
||||
.. cpp:function:: void set_iv(const uint8_t*, size_t len)
|
||||
|
||||
Load IV into the stream cipher state. This should happen after the key is
|
||||
set and before any operation (encrypt/decrypt/seek) is called.
|
||||
|
||||
If the cipher does not support IVs, then a call with ``len`` equal to zero
|
||||
will be accepted and any other length will cause a ``Invalid_IV_Length``
|
||||
exception.
|
||||
|
||||
.. cpp:function:: void seek(uint64_t offset)
|
||||
|
||||
Sets the state of the stream cipher and keystream according to the passed
|
||||
*offset*, exactly as if *offset* bytes had first been encrypted. The key
|
||||
and (if required) the IV have to be set before this can be called. Not all
|
||||
ciphers support seeking; such objects will throw ``Not_Implemented`` in
|
||||
this case.
|
||||
|
||||
.. cpp:function:: void cipher(const uint8_t* in, uint8_t* out, size_t n)
|
||||
|
||||
Processes *n* bytes plain/ciphertext from *in* and writes the result to *out*.
|
||||
|
||||
.. cpp:function:: void cipher1(uint8_t* inout, size_t n)
|
||||
|
||||
Processes *n* bytes plain/ciphertext in place. Acts like :cpp:func:`cipher`\ (inout, inout, n).
|
||||
|
||||
.. cpp:function:: void encipher(std::vector<uint8_t> inout)
|
||||
.. cpp:function:: void encrypt(std::vector<uint8_t> inout)
|
||||
.. cpp:function:: void decrypt(std::vector<uint8_t> inout)
|
||||
|
||||
Processes plain/ciphertext *inout* in place. Acts like :cpp:func:`cipher`\ (inout.data(), inout.data(), inout.size()).
|
||||
|
||||
Code Example
|
||||
-----------------
|
||||
|
||||
The following code encrypts a provided plaintext using ChaCha20.
|
||||
|
||||
.. literalinclude:: /../src/examples/chacha.cpp
|
||||
:language: cpp
|
||||
|
||||
Available Stream Ciphers
|
||||
----------------------------
|
||||
|
||||
Botan provides the following stream ciphers. If in doubt, pick ChaCha20 or CTR(AES-256).
|
||||
|
||||
CTR-BE
|
||||
~~~~~~~
|
||||
|
||||
Counter mode converts a block cipher into a stream cipher. It offers
|
||||
parallel execution and can seek within the output stream, both useful
|
||||
properties.
|
||||
|
||||
CTR mode requires a nonce, which can be any length up to the block size of the
|
||||
underlying cipher. If it is shorter than the block size, sufficient zero bytes
|
||||
are appended.
|
||||
|
||||
It is possible to choose the width of the counter portion, which can improve
|
||||
performance somewhat, but limits the maximum number of bytes that can safely be
|
||||
encrypted. Different protocols have different conventions for the width of the
|
||||
counter portion. This is done by specifying the width (which must be at least 4
|
||||
bytes, allowing to encrypt 2\ :sup:`32` blocks of data) for example using
|
||||
"CTR(AES-256,8)" will select a 64-bit (8 byte) counter.
|
||||
|
||||
(The ``-BE`` suffix refers to big-endian convention for the counter.
|
||||
Little-endian counter mode is rarely used and not currently implemented.)
|
||||
|
||||
OFB
|
||||
~~~~~
|
||||
|
||||
Another stream cipher based on a block cipher. Unlike CTR mode, it does not
|
||||
allow parallel execution or seeking within the output stream. Prefer CTR.
|
||||
|
||||
Available if ``BOTAN_HAS_OFB`` is defined.
|
||||
|
||||
ChaCha
|
||||
~~~~~~~~
|
||||
|
||||
A very fast cipher, now widely deployed in TLS as part of the ChaCha20Poly1305
|
||||
AEAD. Can be used with 8 (fast but dangerous), 12 (balance), or 20 rounds
|
||||
(conservative). Even with 20 rounds, ChaCha is very fast. Use 20 rounds.
|
||||
|
||||
ChaCha supports an optional IV (which defaults to all zeros). It can be of
|
||||
length 64, 96 or (since 2.8) 192 bits. Using ChaCha with a 192 bit nonce is also
|
||||
known as XChaCha.
|
||||
|
||||
Available if ``BOTAN_HAS_CHACHA`` is defined.
|
||||
|
||||
Salsa20
|
||||
~~~~~~~~~
|
||||
|
||||
An earlier iteration of the ChaCha design, this cipher is popular due to its use
|
||||
in the libsodium library. Prefer ChaCha.
|
||||
|
||||
Salsa supports an optional IV (which defaults to all zeros). It can be of length
|
||||
64 or 192 bits. Using Salsa with a 192 bit nonce is also known as XSalsa.
|
||||
|
||||
Available if ``BOTAN_HAS_SALSA20`` is defined.
|
||||
|
||||
SHAKE-128
|
||||
~~~~~~~~~~~~
|
||||
|
||||
This is the SHAKE-128 XOF exposed as a stream cipher. It is slower
|
||||
than ChaCha and somewhat obscure, and was primarily implemented to
|
||||
support a particular post-quantum scheme which is no longer supported.
|
||||
|
||||
SHAKE does not support IVs, nor seeking within the cipher stream.
|
||||
|
||||
Available if ``BOTAN_HAS_SHAKE_CIPHER`` is defined.
|
||||
|
||||
.. warning::
|
||||
|
||||
SHAKE support (as a stream cipher) is deprecated and will be removed
|
||||
in a future major release.
|
||||
|
||||
RC4
|
||||
~~~~
|
||||
|
||||
An old and very widely deployed stream cipher notable for its simplicity. It
|
||||
does not support IVs or seeking within the cipher stream. Compared to modern
|
||||
algorithms like ChaCha20, it is also quite slow.
|
||||
|
||||
.. warning::
|
||||
|
||||
RC4 is prone to numerous attacks. **Avoid in new code** and use only if
|
||||
required for compatibility with existing systems.
|
||||
|
||||
Available if ``BOTAN_HAS_RC4`` is defined.
|
File diff suppressed because it is too large
Load Diff
@ -1,113 +0,0 @@
|
||||
Trusted Platform Module (TPM)
|
||||
==========================================
|
||||
|
||||
.. versionadded:: 1.11.26
|
||||
|
||||
Some computers come with a TPM, which is a small side processor which can
|
||||
perform certain operations which include RSA key generation and signing, a
|
||||
random number generator, accessing a small amount of NVRAM, and a set of PCRs
|
||||
which can be used to measure software state (this is TPMs most famous use, for
|
||||
authenticating a boot sequence).
|
||||
|
||||
The TPM NVRAM and PCR APIs are not supported by Botan at this time, patches welcome.
|
||||
|
||||
Currently only v1.2 TPMs are supported, and the only TPM library supported is
|
||||
TrouSerS (http://trousers.sourceforge.net/). Hopefully both of these limitations
|
||||
will be removed in a future release, in order to support newer TPM v2.0 systems.
|
||||
The current code has been tested with an ST TPM running in a Lenovo laptop.
|
||||
|
||||
Test for TPM support with the macro ``BOTAN_HAS_TPM``, include ``<botan/tpm.h>``.
|
||||
|
||||
First, create a connection to the TPM with a ``TPM_Context``. The context is
|
||||
passed to all other TPM operations, and should remain alive as long as any other
|
||||
TPM object which the context was passed to is still alive, otherwise errors or
|
||||
even an application crash are possible. In the future, the API may change to
|
||||
using ``shared_ptr`` to remove this problem.
|
||||
|
||||
.. cpp:class:: TPM_Context
|
||||
|
||||
.. cpp:function:: TPM_Context(pin_cb cb, const char* srk_password)
|
||||
|
||||
The (somewhat improperly named) pin_cb callback type takes a std::string as
|
||||
an argument, which is an informative message for the user. It should return
|
||||
a string containing the password entered by the user.
|
||||
|
||||
Normally the SRK password is null. Use nullptr to signal this.
|
||||
|
||||
The TPM contains a RNG of unknown design or quality. If that doesn't scare you
|
||||
off, you can use it with ``TPM_RNG`` which implements the standard
|
||||
``RandomNumberGenerator`` interface.
|
||||
|
||||
.. cpp:class:: TPM_RNG
|
||||
|
||||
.. cpp:function:: TPM_RNG(TPM_Context& ctx)
|
||||
|
||||
Initialize a TPM RNG object. After initialization, reading from
|
||||
this RNG reads from the hardware? RNG on the TPM.
|
||||
|
||||
The v1.2 TPM uses only RSA, but because this key is implemented completely in
|
||||
hardware it uses a different private key type, with a somewhat different API to
|
||||
match the TPM's behavior.
|
||||
|
||||
.. cpp:class:: TPM_PrivateKey
|
||||
|
||||
.. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, size_t bits, const char* key_password)
|
||||
|
||||
Create a new RSA key stored on the TPM. The bits should be either 1024
|
||||
or 2048; the TPM interface hypothetically allows larger keys but in
|
||||
practice no v1.2 TPM hardware supports them.
|
||||
|
||||
The TPM processor is not fast, be prepared for this to take a while.
|
||||
|
||||
The key_password is the password to the TPM key ?
|
||||
|
||||
.. cpp:function:: std::string register_key(TPM_Storage_Type storage_type)
|
||||
|
||||
Registers a key with the TPM. The storage_type can be either
|
||||
`TPM_Storage_Type::User` or `TPM_Storage_Type::System`. If System, the
|
||||
key is stored on the TPM itself. If User, it is stored on the local hard
|
||||
drive in a database maintained by an intermediate piece of system
|
||||
software (which actual interacts with the physical TPM on behalf of any
|
||||
number of applications calling the TPM API).
|
||||
|
||||
The TPM has only some limited space to store private keys and may reject
|
||||
requests to store the key.
|
||||
|
||||
In either case the key is encrypted with an RSA key which was generated
|
||||
on the TPM and which it will not allow to be exported. Thus (so goes the
|
||||
theory) without physically attacking the TPM
|
||||
|
||||
Returns a UUID which can be passed back to constructor below.
|
||||
|
||||
.. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::string& uuid, \
|
||||
TPM_Storage_Type storage_type)
|
||||
|
||||
Load a registered key. The UUID was returned by the ``register_key`` function.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> export_blob() const
|
||||
|
||||
Export the key as an encrypted blob. This blob can later be presented
|
||||
back to the same TPM to load the key.
|
||||
|
||||
.. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::vector<uint8_t>& blob)
|
||||
|
||||
Load a TPM key previously exported as a blob with ``export_blob``.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<Public_Key> public_key() const
|
||||
|
||||
Return the public key associated with this TPM private key.
|
||||
|
||||
TPM does not store public keys, nor does it support signature verification.
|
||||
|
||||
.. cpp:function:: TSS_HKEY handle() const
|
||||
|
||||
Returns the bare TSS key handle. Use if you need to call the raw TSS API.
|
||||
|
||||
A ``TPM_PrivateKey`` can be passed to a ``PK_Signer`` constructor and used to
|
||||
sign messages just like any other key. Only PKCS #1 v1.5 signatures are supported
|
||||
by the v1.2 TPM.
|
||||
|
||||
.. cpp:function:: std::vector<std::string> TPM_PrivateKey::registered_keys(TPM_Context& ctx)
|
||||
|
||||
This static function returns the list of all keys (in URL format)
|
||||
registered with the system
|
@ -1,45 +0,0 @@
|
||||
Threshold Secret Sharing
|
||||
========================================
|
||||
|
||||
.. versionadded:: 1.9.1
|
||||
|
||||
Threshold secret sharing allows splitting a secret into ``N`` shares such that
|
||||
``M`` (for specified ``M`` <= ``N``) is sufficient to recover the secret, but an
|
||||
attacker with ``M - 1`` shares cannot derive any information about the secret.
|
||||
|
||||
The implementation in Botan follows an expired Internet draft
|
||||
"draft-mcgrew-tss-03". Several other implementations of this TSS format exist.
|
||||
|
||||
.. cpp:class:: RTSS_Share
|
||||
|
||||
.. cpp:function:: static std::vector<RTSS_Share> split(uint8_t M, uint8_t N, \
|
||||
const uint8_t secret[], uint16_t secret_len, \
|
||||
const std::vector<uint8_t>& identifier, \
|
||||
const std::string& hash_fn, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
Split a secret. The identifier is an optional key identifier which may be
|
||||
up to 16 bytes long. Shorter identifiers are padded with zeros.
|
||||
|
||||
The hash function must be either "SHA-1", "SHA-256", or "None" to disable
|
||||
the checksum.
|
||||
|
||||
This will return a vector of length ``N``, any ``M`` of these shares is
|
||||
sufficient to reconstruct the data.
|
||||
|
||||
.. cpp:function:: static secure_vector<uint8_t> reconstruct(const std::vector<RTSS_Share>& shares)
|
||||
|
||||
Given a sufficient number of shares, reconstruct a secret.
|
||||
|
||||
.. cpp:function:: RTSS_Share(const uint8_t data[], size_t len)
|
||||
|
||||
Read a TSS share as a sequence of bytes.
|
||||
|
||||
.. cpp:function:: const secure_vector<uint8>& data() const
|
||||
|
||||
Return the data of this share.
|
||||
|
||||
.. cpp:function:: uint8_t share_id() const
|
||||
|
||||
Return the share ID which will be in the range 1...255
|
||||
|
@ -1,102 +0,0 @@
|
||||
|
||||
.. _versioning:
|
||||
|
||||
Versioning
|
||||
========================================
|
||||
|
||||
All versions are of the tuple (major,minor,patch).
|
||||
|
||||
As of Botan 2.0.0, Botan uses semantic versioning. The minor number increases if
|
||||
any feature addition is made. The patch version is used to indicate a release
|
||||
where only bug fixes were applied. If an incompatible API change is required,
|
||||
the major version will be increased.
|
||||
|
||||
The library has functions for checking compile-time and runtime versions.
|
||||
|
||||
The build-time version information is defined in `botan/build.h`
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_MAJOR
|
||||
|
||||
The major version of the release.
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_MINOR
|
||||
|
||||
The minor version of the release.
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_PATCH
|
||||
|
||||
The patch version of the release.
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_DATESTAMP
|
||||
|
||||
Expands to an integer of the form YYYYMMDD if this is an official
|
||||
release, or 0 otherwise. For instance, 1.10.1, which was released
|
||||
on July 11, 2011, has a `BOTAN_VERSION_DATESTAMP` of 20110711.
|
||||
|
||||
.. c:macro:: BOTAN_DISTRIBUTION_INFO
|
||||
|
||||
.. versionadded:: 1.9.3
|
||||
|
||||
A macro expanding to a string that is set at build time using the
|
||||
``--distribution-info`` option. It allows a packager of the library
|
||||
to specify any distribution-specific patches. If no value is given
|
||||
at build time, the value is the string "unspecified".
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_VC_REVISION
|
||||
|
||||
.. versionadded:: 1.10.1
|
||||
|
||||
A macro expanding to a string that is set to a revision identifier
|
||||
corresponding to the source, or "unknown" if this could not be
|
||||
determined. It is set for all official releases, and for builds that
|
||||
originated from within a git checkout.
|
||||
|
||||
The runtime version information, and some helpers for compile time
|
||||
version checks, are included in `botan/version.h`
|
||||
|
||||
.. cpp:function:: std::string version_string()
|
||||
|
||||
Returns a single-line string containing relevant information about
|
||||
this build and version of the library in an unspecified format.
|
||||
|
||||
.. cpp:function:: uint32_t version_major()
|
||||
|
||||
Returns the major part of the version.
|
||||
|
||||
.. cpp:function:: uint32_t version_minor()
|
||||
|
||||
Returns the minor part of the version.
|
||||
|
||||
.. cpp:function:: uint32_t version_patch()
|
||||
|
||||
Returns the patch part of the version.
|
||||
|
||||
.. cpp:function:: uint32_t version_datestamp()
|
||||
|
||||
Return the datestamp of the release (or 0 if the current version is
|
||||
not an official release).
|
||||
|
||||
.. cpp:function:: std::string runtime_version_check(uint32_t major, uint32_t minor, uint32_t patch)
|
||||
|
||||
Call this function with the compile-time version being built against, eg::
|
||||
|
||||
Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH)
|
||||
|
||||
It will return an empty string if the versions match, or otherwise
|
||||
an error message indicating the discrepancy. This only is useful in
|
||||
dynamic libraries, where it is possible to compile and run against
|
||||
different versions.
|
||||
|
||||
.. c:macro:: BOTAN_VERSION_CODE_FOR(maj,min,patch)
|
||||
|
||||
Return a value that can be used to compare versions. The current
|
||||
(compile-time) version is available as the macro
|
||||
`BOTAN_VERSION_CODE`. For instance, to choose one code path for
|
||||
version 2.1.0 and later, and another code path for older releases::
|
||||
|
||||
#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,1,0)
|
||||
// 2.1+ code path
|
||||
#else
|
||||
// code path for older versions
|
||||
#endif
|
||||
|
@ -1,954 +0,0 @@
|
||||
.. _x509_certificates:
|
||||
|
||||
X.509 Certificates and CRLs
|
||||
=================================
|
||||
|
||||
A certificate is a binding between some identifying information
|
||||
(called a *subject*) and a public key. This binding is asserted by a
|
||||
signature on the certificate, which is placed there by some authority
|
||||
(the *issuer*) that at least claims that it knows the subject named in
|
||||
the certificate really "owns" the private key corresponding to the
|
||||
public key in the certificate.
|
||||
|
||||
The major certificate format in use today is X.509v3, used for instance in the
|
||||
:doc:`tls` protocol. A X.509 certificate is represented by the class
|
||||
``X509_Certificate``. The data of an X.509 certificate is stored as a
|
||||
``shared_ptr`` to a structure containing the decoded information. So copying
|
||||
``X509_Certificate`` objects is quite cheap.
|
||||
|
||||
|
||||
.. cpp:class:: X509_Certificate
|
||||
|
||||
.. cpp:function:: X509_Certificate(const std::string& filename)
|
||||
|
||||
Load a certificate from a file. PEM or DER is accepted.
|
||||
|
||||
.. cpp:function:: X509_Certificate(const std::vector<uint8_t>& in)
|
||||
|
||||
Load a certificate from a byte string.
|
||||
|
||||
.. cpp:function:: X509_Certificate(DataSource& source)
|
||||
|
||||
Load a certificate from an abstract ``DataSource``.
|
||||
|
||||
.. cpp:function:: X509_DN subject_dn() const
|
||||
|
||||
Returns the distinguished name (DN) of the certificate's subject. This is
|
||||
the primary place where information about the subject of the certificate is
|
||||
stored. However "modern" information that doesn't fit in the X.500
|
||||
framework, such as DNS name, email, IP address, or XMPP address, appears
|
||||
instead in the subject alternative name.
|
||||
|
||||
.. cpp:function:: X509_DN issuer_dn() const
|
||||
|
||||
Returns the distinguished name (DN) of the certificate's issuer, ie the CA
|
||||
that issued this certificate.
|
||||
|
||||
.. cpp:function:: const AlternativeName& subject_alt_name() const
|
||||
|
||||
Return the subjects alternative name. This is used to store
|
||||
values like associated URIs, DNS addresses, and email addresses.
|
||||
|
||||
.. cpp:function:: const AlternativeName& issuer_alt_name() const
|
||||
|
||||
Return alternative names for the issuer.
|
||||
|
||||
.. cpp:function:: std::unique_ptr<Public_Key> load_subject_public_key() const
|
||||
|
||||
Deserialize the stored public key and return a new object. This
|
||||
might throw, if it happens that the public key object stored in
|
||||
the certificate is malformed in some way, or in the case that the
|
||||
public key algorithm used is not supported by the library.
|
||||
|
||||
See :ref:`serializing_public_keys` for more information about what to do
|
||||
with the returned object. It may be any type of key, in principle, though
|
||||
RSA and ECDSA are most common.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> subject_public_key_bits() const
|
||||
|
||||
Return the binary encoding of the subject public key. This value (or a hash of
|
||||
it) is used in various protocols, eg for public key pinning.
|
||||
|
||||
.. cpp:function:: AlgorithmIdentifier subject_public_key_algo() const
|
||||
|
||||
Return an algorithm identifier that identifies the algorithm used in the
|
||||
subject's public key.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> serial_number() const
|
||||
|
||||
Return the certificates serial number. The tuple of issuer DN and
|
||||
serial number should be unique.
|
||||
|
||||
.. cpp:function:: std::vector<uint8> raw_subject_dn() const
|
||||
|
||||
Return the binary encoding of the subject DN.
|
||||
|
||||
.. cpp:function:: std::vector<uint8> raw_issuer_dn() const
|
||||
|
||||
Return the binary encoding of the issuer DN.
|
||||
|
||||
.. cpp:function:: X509_Time not_before() const
|
||||
|
||||
Returns the point in time the certificate becomes valid
|
||||
|
||||
.. cpp:function:: X509_Time not_after() const
|
||||
|
||||
Returns the point in time the certificate expires
|
||||
|
||||
.. cpp:function:: const Extensions& v3_extensions() const
|
||||
|
||||
Returns all extensions of this certificate. You can use this
|
||||
to examine any extension data associated with the certificate,
|
||||
including custom extensions the library doesn't know about.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> authority_key_id() const
|
||||
|
||||
Return the authority key id, if set. This is an arbitrary string; in the
|
||||
issuing certificate this will be the subject key id.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> subject_key_id() const
|
||||
|
||||
Return the subject key id, if set.
|
||||
|
||||
.. cpp:function:: bool allowed_extended_usage(const OID& usage) const
|
||||
|
||||
Return true if and only if the usage OID appears in the extended key usage
|
||||
extension. Also will return true if the extended key usage extension is
|
||||
not used in the current certificate.
|
||||
|
||||
.. cpp:function:: std::vector<OID> extended_key_usage() const
|
||||
|
||||
Return the list of extended key usages. May be empty.
|
||||
|
||||
.. cpp:function:: std::string fingerprint(const std::string& hash_fn = "SHA-1") const
|
||||
|
||||
Return a fingerprint for the certificate, which is basically just a hash
|
||||
of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash
|
||||
function is allowed.
|
||||
|
||||
.. cpp:function:: Key_Constraints constraints() const
|
||||
|
||||
Returns a basic list of constraints which govern usage of the
|
||||
key embedded in this certificate.
|
||||
|
||||
The Key_Constraints is a class that behaves somewhat like an
|
||||
``enum``. The easiest way to use it is with its ``includes``
|
||||
method. For example::
|
||||
|
||||
constraints().includes(Key_Constraints::DigitalSignature)
|
||||
|
||||
checks if the certificate key is valid for generating digital
|
||||
signatures.
|
||||
|
||||
.. cpp:function:: bool matches_dns_name(const std::string& name) const
|
||||
|
||||
Check if the certificate's subject alternative name DNS fields
|
||||
match ``name``. This function also handles wildcard certificates.
|
||||
|
||||
.. cpp:function:: std::string to_string() const
|
||||
|
||||
Returns a free-form human readable string describing the certificate.
|
||||
|
||||
.. cpp:function:: std::string PEM_encode() const
|
||||
|
||||
Returns the PEM encoding of the certificate
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> BER_encode() const
|
||||
|
||||
Returns the DER/BER encoding of the certificate
|
||||
|
||||
X.509 Distinguished Names
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. cpp:class:: X509_DN
|
||||
|
||||
.. cpp:function:: bool has_field(const std::string& attr) const
|
||||
|
||||
Returns true if ``get_attribute`` or ``get_first_attribute`` will return a value.
|
||||
|
||||
.. cpp:function:: std::vector<std::string> get_attribute(const std::string& attr) const
|
||||
|
||||
Return all attributes associated with a certain attribute type.
|
||||
|
||||
.. cpp:function:: std::string get_first_attribute(const std::string& attr) const
|
||||
|
||||
Like ``get_attribute`` but returns just the first attribute, or
|
||||
empty if the DN has no attribute of the specified type.
|
||||
|
||||
.. cpp:function:: std::multimap<OID, std::string> get_attributes() const
|
||||
|
||||
Get all attributes of the DN. The OID maps to a DN component such as
|
||||
2.5.4.10 ("Organization"), and the strings are UTF-8 encoded.
|
||||
|
||||
.. cpp:function:: std::multimap<std::string, std::string> contents() const
|
||||
|
||||
Similar to ``get_attributes``, but the OIDs are decoded to strings.
|
||||
|
||||
.. cpp:function:: void add_attribute(const std::string& key, const std::string& val)
|
||||
|
||||
Add an attribute to a DN.
|
||||
|
||||
.. cpp:function:: void add_attribute(const OID& oid, const std::string& val)
|
||||
|
||||
Add an attribute to a DN using an OID instead of string-valued attribute type.
|
||||
|
||||
The ``X509_DN`` type also supports iostream extraction and insertion operators,
|
||||
for formatted input and output.
|
||||
|
||||
X.509v3 Extensions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
X.509v3 specifies a large number of possible extensions. Botan supports some,
|
||||
but by no means all of them. The following listing lists which X.509v3
|
||||
extensions are supported and notes areas where there may be problems with the
|
||||
handling.
|
||||
|
||||
- Key Usage and Extended Key Usage: No problems known.
|
||||
|
||||
- Basic Constraints: No problems known. A self-signed v1 certificate
|
||||
is assumed to be a CA, while a v3 certificate is marked as a CA if
|
||||
and only if the basic constraints extension is present and set for
|
||||
a CA cert.
|
||||
|
||||
- Subject Alternative Names: Only the "rfc822Name", "dNSName", and
|
||||
"uniformResourceIdentifier" and raw IPv4 fields will be stored; all
|
||||
others are ignored.
|
||||
|
||||
- Issuer Alternative Names: Same restrictions as the Subject
|
||||
Alternative Names extension. New certificates generated by Botan
|
||||
never include the issuer alternative name.
|
||||
|
||||
- Authority Key Identifier: Only the version using KeyIdentifier is
|
||||
supported. If the GeneralNames version is used and the extension is
|
||||
critical, an exception is thrown. If both the KeyIdentifier and GeneralNames
|
||||
versions are present, then the KeyIdentifier will be used, and the
|
||||
GeneralNames ignored.
|
||||
|
||||
- Subject Key Identifier: No problems known.
|
||||
|
||||
- Name Constraints: No problems known (though encoding is not supported).
|
||||
|
||||
Any unknown critical extension in a certificate will lead to an
|
||||
exception during path validation.
|
||||
|
||||
Extensions are handled by a special class taking care of encoding
|
||||
and decoding. It also supports encoding and decoding of custom extensions.
|
||||
To do this, it internally keeps two lists of extensions. Different lookup
|
||||
functions are provided to search them.
|
||||
|
||||
.. note::
|
||||
|
||||
Validation of custom extensions during path validation is currently not supported.
|
||||
|
||||
.. cpp:class:: Extensions
|
||||
|
||||
.. cpp:function:: void add(Certificate_Extension* extn, bool critical = false)
|
||||
|
||||
Adds a new extension to the extensions object. If an extension of the same
|
||||
type already exists, ``extn`` will replace it. If ``critical`` is true the
|
||||
extension will be marked as critical in the encoding.
|
||||
|
||||
.. cpp:function:: bool add_new(Certificate_Extension* extn, bool critical = false)
|
||||
|
||||
Like ``add`` but an existing extension will not be replaced. Returns true if the
|
||||
extension was used, false if an extension of the same type was already in place.
|
||||
|
||||
.. cpp:function:: void replace(Certificate_Extension* extn, bool critical = false)
|
||||
|
||||
Adds an extension to the list or replaces it, if the same
|
||||
extension was already added
|
||||
|
||||
.. cpp:function:: std::unique_ptr<Certificate_Extension> get(const OID& oid) const
|
||||
|
||||
Searches for an extension by OID and returns the result
|
||||
|
||||
.. cpp:function:: template<typename T> \
|
||||
std::unique_ptr<T> get_raw(const OID& oid)
|
||||
|
||||
Searches for an extension by OID and returns the result.
|
||||
Only the unknown extensions, that is, extensions types that are not
|
||||
listed above, are searched for by this function.
|
||||
|
||||
.. cpp:function:: std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const
|
||||
|
||||
Returns the list of extensions together with the corresponding
|
||||
criticality flag. Only contains the supported extension types
|
||||
listed above.
|
||||
|
||||
.. cpp:function:: std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const
|
||||
|
||||
Returns the list of extensions as raw, encoded bytes
|
||||
together with the corresponding criticality flag.
|
||||
Contains all extensions, known as well as unknown extensions.
|
||||
|
||||
Certificate Revocation Lists
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It will occasionally happen that a certificate must be revoked before
|
||||
its expiration date. Examples of this happening include the private
|
||||
key being compromised, or the user to which it has been assigned
|
||||
leaving an organization. Certificate revocation lists are an answer to
|
||||
this problem (though online certificate validation techniques are
|
||||
starting to become somewhat more popular). Every once in a while the
|
||||
CA will release a new CRL, listing all certificates that have been
|
||||
revoked. Also included is various pieces of information like what time
|
||||
a particular certificate was revoked, and for what reason. In most
|
||||
systems, it is wise to support some form of certificate revocation,
|
||||
and CRLs handle this easily.
|
||||
|
||||
For most users, processing a CRL is quite easy. All you have to do is
|
||||
call the constructor, which will take a filename (or a
|
||||
``DataSource&``). The CRLs can either be in raw BER/DER, or in PEM
|
||||
format; the constructor will figure out which format without any extra
|
||||
information. For example::
|
||||
|
||||
X509_CRL crl1("crl1.der");
|
||||
|
||||
DataSource_Stream in("crl2.pem");
|
||||
X509_CRL crl2(in);
|
||||
|
||||
After that, pass the ``X509_CRL`` object to a ``Certificate_Store`` object
|
||||
with
|
||||
|
||||
.. cpp:function:: void Certificate_Store::add_crl(const X509_CRL& crl)
|
||||
|
||||
and all future verifications will take into account the provided CRL.
|
||||
|
||||
Certificate Stores
|
||||
----------------------------------------
|
||||
|
||||
An object of type ``Certificate_Store`` is a generalized interface to
|
||||
an external source for certificates (and CRLs). Examples of such a
|
||||
store would be one that looked up the certificates in a SQL database,
|
||||
or by contacting a CGI script running on a HTTP server. There are
|
||||
currently three mechanisms for looking up a certificate, and one for
|
||||
retrieving CRLs. By default, most of these mechanisms will return an
|
||||
empty ``std::optional`` of ``X509_Certificate``. This storage mechanism
|
||||
is *only* queried when doing certificate validation: it allows you to
|
||||
distribute only the root key with an application, and let some online
|
||||
method handle getting all the other certificates that are needed to
|
||||
validate an end entity certificate. In particular, the search routines
|
||||
will not attempt to access the external database.
|
||||
|
||||
The certificate lookup methods are ``find_cert`` (by Subject
|
||||
Distinguished Name and optional Subject Key Identifier) and
|
||||
``find_cert_by_pubkey_sha1`` (by SHA-1 hash of the certificate's
|
||||
public key). The Subject Distinguished Name is given as a ``X509_DN``,
|
||||
while the SKID parameter takes a ``std::vector<uint8_t>`` containing
|
||||
the subject key identifier in raw binary. Both lookup methods are
|
||||
mandatory to implement.
|
||||
|
||||
Finally, there is a method for finding a CRL, called ``find_crl_for``,
|
||||
that takes an ``X509_Certificate`` object, and returns a
|
||||
``std::optional`` of ``X509_CRL``. The ``std::optional`` return
|
||||
type makes it easy to return no CRLs by returning ``nullopt``
|
||||
(eg, if the certificate store doesn't support retrieving CRLs).
|
||||
Implementing the function is optional, and by default will return
|
||||
``nullopt``.
|
||||
|
||||
Certificate stores are used in the :doc:`tls` module to store a
|
||||
list of trusted certificate authorities.
|
||||
|
||||
.. note::
|
||||
|
||||
In the 2.x library, the certificate store interface relied on
|
||||
``shared_ptr<X509_Certificate>`` to avoid copies. However since
|
||||
2.4.0, the ``X509_Certificate`` was internally shared, and thus the
|
||||
outer ``shared_ptr`` was just a cause of needless runtime overhead
|
||||
and API complexity. Starting in version 3.0, the certificate store
|
||||
interface is defined in terms of plain ``X509_Certificate``.
|
||||
|
||||
In Memory Certificate Store
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The in memory certificate store keeps all objects in memory only.
|
||||
Certificates can be loaded from disk initially, but also added
|
||||
later.
|
||||
|
||||
.. cpp:class:: Certificate_Store_In_Memory
|
||||
|
||||
.. cpp:function:: Certificate_Store_In_Memory(const std::string& dir)
|
||||
|
||||
Attempt to parse all files in ``dir`` (including subdirectories)
|
||||
as certificates. Ignores errors.
|
||||
|
||||
.. cpp:function:: Certificate_Store_In_Memory(const X509_Certificate& cert)
|
||||
|
||||
Adds given certificate to the store
|
||||
|
||||
.. cpp:function:: Certificate_Store_In_Memory()
|
||||
|
||||
Create an empty store
|
||||
|
||||
.. cpp:function:: void add_certificate(const X509_Certificate& cert)
|
||||
|
||||
Add a certificate to the store
|
||||
|
||||
.. cpp:function:: void add_crl(const X509_CRL& crl)
|
||||
|
||||
Add a certificate revocation list (CRL) to the store.
|
||||
|
||||
System Certificate Stores
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
An interface to use the system provided certificate stores is available for
|
||||
Unix, macOS and Windows systems, ``System_Certificate_Store``
|
||||
|
||||
Flatfile Certificate Stores
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``Flatfile_Certificate_Store`` is an implementation of certificate store that
|
||||
reads certificates as files from a directory. This is also used as the
|
||||
implementation of the Unix/Linux system certificate store.
|
||||
|
||||
The constructor takes a path to the directory to read, along with an optional
|
||||
boolean indicating if non-CA certificates should be ignored.
|
||||
|
||||
SQL-backed Certificate Stores
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The SQL-backed certificate stores store all objects in an SQL database. They
|
||||
also additionally provide private key storage and revocation of individual
|
||||
certificates.
|
||||
|
||||
.. cpp:class:: Certificate_Store_In_SQL
|
||||
|
||||
.. cpp:function:: Certificate_Store_In_SQL(const std::shared_ptr<SQL_Database> db, \
|
||||
const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "")
|
||||
|
||||
Create or open an existing certificate store from an SQL database.
|
||||
The password in ``passwd`` will be used to encrypt private keys.
|
||||
|
||||
.. cpp:function:: bool insert_cert(const X509_Certificate& cert)
|
||||
|
||||
Inserts ``cert`` into the store. Returns `false` if the certificate is
|
||||
already known and `true` if insertion was successful.
|
||||
|
||||
.. cpp:function:: remove_cert(const X509_Certificate& cert)
|
||||
|
||||
Removes ``cert`` from the store. Returns `false` if the certificate could not
|
||||
be found and `true` if removal was successful.
|
||||
|
||||
.. cpp:function:: std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const
|
||||
|
||||
Returns the private key for "cert" or an empty shared_ptr if none was found
|
||||
|
||||
.. cpp:function:: std::vector<X509_Certificate> find_certs_for_key(const Private_Key& key) const
|
||||
|
||||
Returns all certificates for private key ``key``
|
||||
|
||||
.. cpp:function:: bool insert_key(const X509_Certificate& cert, const Private_Key& key)
|
||||
|
||||
Inserts ``key`` for ``cert`` into the store, returns `false` if the key is
|
||||
already known and `true` if insertion was successful.
|
||||
|
||||
.. cpp:function:: void remove_key(const Private_Key& key)
|
||||
|
||||
Removes ``key`` from the store
|
||||
|
||||
.. cpp:function:: void revoke_cert(const X509_Certificate&, CRL_Code, \
|
||||
const X509_Time& time = X509_Time())
|
||||
|
||||
Marks ``cert`` as revoked starting from ``time``
|
||||
|
||||
.. cpp:function:: void affirm_cert(const X509_Certificate&)
|
||||
|
||||
Reverses the revocation for ``cert``
|
||||
|
||||
.. cpp:function:: std::vector<X509_CRL> generate_crls() const
|
||||
|
||||
Generates CRLs for all certificates marked as revoked.
|
||||
A CRL is returned for each unique issuer DN.
|
||||
|
||||
The ``Certificate_Store_In_SQL`` class operates on an abstract ``SQL_Database``
|
||||
object. If support for sqlite3 was enabled at build time, Botan includes an
|
||||
implementation of this interface for sqlite3, and a subclass of
|
||||
``Certificate_Store_In_SQL`` which creates or opens a sqlite3 database.
|
||||
|
||||
.. cpp:class:: Certificate_Store_In_SQLite
|
||||
|
||||
.. cpp:function:: Certificate_Store_In_SQLite(const std::string& db_path, \
|
||||
const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "")
|
||||
|
||||
Create or open an existing certificate store from an sqlite database file.
|
||||
The password in ``passwd`` will be used to encrypt private keys.
|
||||
|
||||
Path Validation
|
||||
----------------------------------------
|
||||
|
||||
The process of validating a certificate chain up to a trusted root is
|
||||
called `path validation`, and in botan that operation is handled by a
|
||||
set of functions in ``x509path.h`` named ``x509_path_validate``:
|
||||
|
||||
.. cpp:function:: Path_Validation_Result \
|
||||
x509_path_validate(const X509_Certificate& end_cert, \
|
||||
const Path_Validation_Restrictions& restrictions, \
|
||||
const Certificate_Store& store, const std::string& hostname = "", \
|
||||
Usage_Type usage = Usage_Type::UNSPECIFIED, \
|
||||
std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \
|
||||
std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \
|
||||
const std::vector<std::optional<OCSP::Response>>& ocsp_resp = std::vector<std::optional<OCSP::Response>>())
|
||||
|
||||
The last five parameters are optional. ``hostname`` specifies a hostname which is
|
||||
matched against the subject DN in ``end_cert`` according to RFC 6125.
|
||||
An empty hostname disables hostname validation.
|
||||
``usage`` specifies key usage restrictions that are compared
|
||||
to the key usage fields in `end_cert` according to RFC 5280, if not set to
|
||||
``UNSPECIFIED``. ``validation_time`` allows setting the time point at which all certificates
|
||||
are validated. This is really only useful for testing. The default is the
|
||||
current system clock's current time. ``ocsp_timeout`` sets the timeout for
|
||||
OCSP requests. The default of 0 disables OCSP checks completely.
|
||||
``ocsp_resp`` allows adding additional OCSP responses retrieved from outside
|
||||
of the path validation. Note that OCSP online checks are done only
|
||||
as long as the http_util module was compiled in. Availability of online
|
||||
OCSP checks can be checked using the macro BOTAN_HAS_ONLINE_REVOCATION_CHECKS.
|
||||
|
||||
For the different flavors of ``x509_path_validate``, check ``x509path.h``.
|
||||
|
||||
The result of the validation is returned as a class:
|
||||
|
||||
.. cpp:class:: Path_Validation_Result
|
||||
|
||||
Specifies the result of the validation
|
||||
|
||||
.. cpp:function:: bool successful_validation() const
|
||||
|
||||
Returns true if a certificate path from *end_cert* to a trusted
|
||||
root was found and all path validation checks passed.
|
||||
|
||||
.. cpp:function:: std::string result_string() const
|
||||
|
||||
Returns a descriptive string of the validation status (for
|
||||
instance "Verified", "Certificate is not yet valid", or
|
||||
"Signature error"). This is the string value of
|
||||
the `result` function below.
|
||||
|
||||
.. cpp:function:: const X509_Certificate& trust_root() const
|
||||
|
||||
If the validation was successful, returns the certificate which
|
||||
is acting as the trust root for *end_cert*.
|
||||
|
||||
.. cpp:function:: const std::vector<X509_Certificate>& cert_path() const
|
||||
|
||||
Returns the full certificate path starting with the end entity
|
||||
certificate and ending in the trust root.
|
||||
|
||||
.. cpp:function:: Certificate_Status_Code result() const
|
||||
|
||||
Returns the 'worst' error that occurred during validation. For
|
||||
instance, we do not want an expired certificate with an invalid
|
||||
signature to be reported to the user as being simply expired (a
|
||||
relatively innocuous and common error) when the signature isn't
|
||||
even valid.
|
||||
|
||||
.. cpp:function:: const std::vector<std::set<Certificate_Status_Code>>& all_statuses() const
|
||||
|
||||
For each certificate in the chain, returns a set of status which
|
||||
indicate all errors which occurred during validation. This is
|
||||
primarily useful for diagnostic purposes.
|
||||
|
||||
.. cpp:function:: std::set<std::string> trusted_hashes() const
|
||||
|
||||
Returns the set of all cryptographic hash functions which are
|
||||
implicitly trusted for this validation to be correct.
|
||||
|
||||
|
||||
A ``Path_Validation_Restrictions`` is passed to the path
|
||||
validator and specifies restrictions and options for the validation
|
||||
step. The two constructors are:
|
||||
|
||||
.. cpp:function:: Path_Validation_Restrictions(bool require_rev, \
|
||||
size_t minimum_key_strength, \
|
||||
bool ocsp_all_intermediates, \
|
||||
const std::set<std::string>& trusted_hashes)
|
||||
|
||||
If `require_rev` is true, then any path without revocation
|
||||
information (CRL or OCSP check) is rejected with the code
|
||||
`NO_REVOCATION_DATA`. The `minimum_key_strength` parameter
|
||||
specifies the minimum strength of public key signature we will
|
||||
accept is. The set of hash names `trusted_hashes` indicates which
|
||||
hash functions we'll accept for cryptographic signatures. Any
|
||||
untrusted hash will cause the error case `UNTRUSTED_HASH`.
|
||||
|
||||
.. cpp:function:: Path_Validation_Restrictions(bool require_rev = false, \
|
||||
size_t minimum_key_strength = 80, \
|
||||
bool ocsp_all_intermediates = false)
|
||||
|
||||
A variant of the above with some convenient defaults. The current
|
||||
default `minimum_key_strength` of 80 roughly corresponds to 1024
|
||||
bit RSA. The set of trusted hashes is set to all SHA-2 variants,
|
||||
and, if `minimum_key_strength` is less than or equal to 80, then
|
||||
SHA-1 signatures will also be accepted.
|
||||
|
||||
Creating New Certificates
|
||||
---------------------------------
|
||||
|
||||
A CA is represented by the type ``X509_CA``, which can be found in
|
||||
``x509_ca.h``. A CA always needs its own certificate, which can either
|
||||
be a self-signed certificate (see below on how to create one) or one
|
||||
issued by another CA (see the section on PKCS #10 requests). Creating
|
||||
a CA object is done by the following constructor:
|
||||
|
||||
.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \
|
||||
const Private_Key& key, \
|
||||
const std::string& hash_fn, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
The private ``key`` is the private key corresponding to the public key in the
|
||||
CA's certificate. ``hash_fn`` is the name of the hash function to use
|
||||
for signing, e.g., `SHA-256`. ``rng`` is queried for random during signing.
|
||||
|
||||
There is an alternative constructor that lets you set additional options, namely
|
||||
the padding scheme that will be used by the X509_CA object to sign certificates
|
||||
and certificate revocation lists. If the padding is not set explicitly, the CA
|
||||
will use some default. The only time you need this alternate interface is
|
||||
for creating RSA-PSS certificates.
|
||||
|
||||
.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \
|
||||
const Private_Key& key, \
|
||||
const std::string& hash_fn, \
|
||||
const std::string& padding_fn, \
|
||||
RandomNumberGenerator& rng)
|
||||
|
||||
Requests for new certificates are supplied to a CA in the form of PKCS
|
||||
#10 certificate requests (called a ``PKCS10_Request`` object in
|
||||
Botan). These are decoded in a similar manner to
|
||||
certificates/CRLs/etc. A request is vetted by humans (who somehow
|
||||
verify that the name in the request corresponds to the name of the
|
||||
entity who requested it), and then signed by a CA key, generating a
|
||||
new certificate:
|
||||
|
||||
.. cpp:function:: X509_Certificate \
|
||||
X509_CA::sign_request(const PKCS10_Request& req, \
|
||||
RandomNumberGenerator& rng, \
|
||||
const X509_Time& not_before, \
|
||||
const X509_Time& not_after)
|
||||
|
||||
If you need more control over the signing process, you can use the methods
|
||||
|
||||
.. cpp:function:: static X509_Certificate X509_CA::make_cert(PK_Signer& signer, \
|
||||
RandomNumberGenerator& rng, \
|
||||
const BigInt& serial_number, \
|
||||
const AlgorithmIdentifier& sig_algo, \
|
||||
const std::vector<uint8_t>& pub_key, \
|
||||
const X509_Time& not_before, \
|
||||
const X509_Time& not_after, \
|
||||
const X509_DN& issuer_dn, \
|
||||
const X509_DN& subject_dn, \
|
||||
const Extensions& extensions)
|
||||
|
||||
.. cpp:function:: static Extensions X509_CA::choose_extensions(const PKCS10_Request& req, \
|
||||
const X509_Certificate& ca_certificate, \
|
||||
const std::string& hash_fn)
|
||||
|
||||
Returns the extensions that would be created by sign_request if it was used.
|
||||
You can call this and then modify the extensions list before invoking
|
||||
:cpp:func:`X509_CA::make_cert`
|
||||
|
||||
Generating CRLs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As mentioned previously, the ability to process CRLs is highly
|
||||
important in many PKI systems. In fact, according to strict X.509
|
||||
rules, you must not validate any certificate if the appropriate CRLs
|
||||
are not available (though hardly any systems are that strict). In any
|
||||
case, a CA should have a valid CRL available at all times.
|
||||
|
||||
Of course, you might be wondering what to do if no certificates have
|
||||
been revoked. Never fear; empty CRLs, which revoke nothing at all, can
|
||||
be issued. To generate a new, empty CRL, just call
|
||||
|
||||
.. cpp:function:: X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, \
|
||||
uint32_t next_update = 0)
|
||||
|
||||
This function will return a new, empty CRL. The ``next_update`` parameter is
|
||||
the number of seconds before the CRL expires. If it is set to the (default)
|
||||
value of zero, then a reasonable default (currently 7 days) will be used.
|
||||
|
||||
On the other hand, you may have issued a CRL before. In that case, you will
|
||||
want to issue a new CRL that contains all previously revoked
|
||||
certificates, along with any new ones. This is done by calling
|
||||
|
||||
.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, \
|
||||
std::vector<CRL_Entry> new_entries, RandomNumberGenerator& rng, \
|
||||
size_t next_update = 0)
|
||||
|
||||
Where ``last_crl`` is the last CRL this CA issued, and
|
||||
``new_entries`` is a list of any newly revoked certificates. The
|
||||
function returns a new ``X509_CRL`` to make available for
|
||||
clients.
|
||||
|
||||
The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial
|
||||
number of the revoked certificate. As serial numbers are never repeated, the
|
||||
pairing of an issuer and a serial number (should) distinctly identify any
|
||||
certificate. In this case, we represent the serial number as a
|
||||
``secure_vector<uint8_t>`` called ``serial``. There are two additional (optional)
|
||||
values, an enumeration called ``CRL_Code`` that specifies the reason for
|
||||
revocation (``reason``), and an object that represents the time that the
|
||||
certificate became invalid (if this information is known).
|
||||
|
||||
If you wish to remove an old entry from the CRL, insert a new entry for the
|
||||
same cert, with a ``reason`` code of ``REMOVE_FROM_CRL``. For example, if a
|
||||
revoked certificate has expired 'normally', there is no reason to continue to
|
||||
explicitly revoke it, since clients will reject the cert as expired in any
|
||||
case.
|
||||
|
||||
Self-Signed Certificates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Generating a new self-signed certificate can often be useful, for
|
||||
example when setting up a new root CA, or for use in specialized
|
||||
protocols. The library provides a utility function for this:
|
||||
|
||||
.. cpp:function:: X509_Certificate create_self_signed_cert( \
|
||||
const X509_Cert_Options& opts, const Private_Key& key, \
|
||||
const std::string& hash_fn, RandomNumberGenerator& rng)
|
||||
|
||||
Where ``key`` is the private key you wish to use (the public key,
|
||||
used in the certificate itself is extracted from the private key),
|
||||
and ``opts`` is an structure that has various bits of information
|
||||
that will be used in creating the certificate (this structure, and
|
||||
its use, is discussed below).
|
||||
|
||||
Creating PKCS #10 Requests
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Also in ``x509self.h``, there is a function for generating new PKCS #10
|
||||
certificate requests:
|
||||
|
||||
.. cpp:function:: PKCS10_Request create_cert_req( \
|
||||
const X509_Cert_Options& opts, const Private_Key& key, \
|
||||
const std::string& hash_fn, RandomNumberGenerator& rng)
|
||||
|
||||
This function acts quite similarly to
|
||||
:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS
|
||||
#10 certificate request. After creating it, one would typically
|
||||
transmit it to a CA, who signs it and returns a freshly minted X.509
|
||||
certificate.
|
||||
|
||||
.. cpp:function:: PKCS10_Request PKCS10_Request::create(const Private_Key& key, \
|
||||
const X509_DN& subject_dn, \
|
||||
const Extensions& extensions, \
|
||||
const std::string& hash_fn, \
|
||||
RandomNumberGenerator& rng, \
|
||||
const std::string& padding_scheme = "", \
|
||||
const std::string& challenge = "")
|
||||
|
||||
This function (added in 2.5) is similar to ``create_cert_req`` but allows
|
||||
specifying all the parameters directly. In fact ``create_cert_req`` just
|
||||
creates the DN and extensions from the options, then uses this call to
|
||||
actually create the ``PKCS10_Request`` object.
|
||||
|
||||
|
||||
Certificate Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
What is this ``X509_Cert_Options`` thing we've been passing around?
|
||||
It's a class representing a bunch of information that will end up
|
||||
being stored into the certificate. This information comes in 3 major
|
||||
flavors: information about the subject (CA or end-user), the validity
|
||||
period of the certificate, and restrictions on the usage of the
|
||||
certificate. For special cases, you can also add custom X.509v3
|
||||
extensions.
|
||||
|
||||
First and foremost is a number of ``std::string`` members, which
|
||||
contains various bits of information about the user: ``common_name``,
|
||||
``serial_number``, ``country``, ``organization``, ``org_unit``,
|
||||
``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many
|
||||
of these as possible should be filled it (especially an email
|
||||
address), though the only required ones are ``common_name`` and
|
||||
``country``.
|
||||
|
||||
Additionally there are a small selection of ``std::vector<std::string>``
|
||||
members, which allow space for repeating elements:
|
||||
``more_org_units`` and ``more_dns``.
|
||||
|
||||
There is another value that is only useful when creating a PKCS #10
|
||||
request, which is called ``challenge``. This is a challenge password,
|
||||
which you can later use to request certificate revocation (*if* the CA
|
||||
supports doing revocations in this manner).
|
||||
|
||||
Then there is the validity period; these are set with ``not_before``
|
||||
and ``not_after``. Both of these functions also take a
|
||||
``std::string``, which specifies when the certificate should start
|
||||
being valid, and when it should stop being valid. If you don't set the
|
||||
starting validity period, it will automatically choose the current
|
||||
time. If you don't set the ending time, it will choose the starting
|
||||
time plus a default time period. The arguments to these functions
|
||||
specify the time in the following format: "2002/11/27 1:50:14". The
|
||||
time is in 24-hour format, and the date is encoded as
|
||||
year/month/day. The date must be specified, but you can omit the time
|
||||
or trailing parts of it, for example "2002/11/27 1:50" or
|
||||
"2002/11/27".
|
||||
|
||||
Third, you can set constraints on a key. The one you're mostly likely
|
||||
to want to use is to create (or request) a CA certificate, which can
|
||||
be done by calling the member function ``CA_key``. This should only be
|
||||
used when needed.
|
||||
|
||||
Moreover, you can specify the padding scheme to be used when digital signatures
|
||||
are computed by calling function ``set_padding_scheme`` with a string
|
||||
representing the padding scheme. This way, you can control the padding scheme
|
||||
for self-signed certificates and PKCS #10 requests. The padding scheme used by
|
||||
a CA when building a certificate or a certificate revocation list can be set in
|
||||
the ``X509_CA`` constructor. The supported padding schemes can be found in
|
||||
src/lib/pubkey/padding.cpp. Some alternative names for the padding schemes are
|
||||
understood, as well.
|
||||
|
||||
Other constraints can be set by calling the member functions
|
||||
``add_constraints`` and ``add_ex_constraints``. The first takes a
|
||||
``Key_Constraints`` value, and replaces any previously set value. If
|
||||
no value is set, then the certificate key is marked as being valid for
|
||||
any usage. You can set it to any of the following (for more than one
|
||||
usage, OR them together): ``DigitalSignature``, ``NonRepudiation``,
|
||||
``KeyEncipherment``, ``DataEncipherment``, ``KeyAgreement``,
|
||||
``KeyCertSign``, ``CrlSign``, ``EncipherOnly``, or ``DecipherOnly``.
|
||||
Many of these have quite special semantics, so you should either
|
||||
consult the appropriate standards document (such as RFC 5280), or just
|
||||
not call ``add_constraints``, in which case the appropriate values
|
||||
will be chosen for you based on the key type.
|
||||
|
||||
The second function, ``add_ex_constraints``, allows you to specify an
|
||||
OID that has some meaning with regards to restricting the key to
|
||||
particular usages. You can, if you wish, specify any OID you like, but
|
||||
there is a set of standard ones that other applications will be able
|
||||
to understand. These are the ones specified by the PKIX standard, and
|
||||
are named "PKIX.ServerAuth" (for TLS server authentication),
|
||||
"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning",
|
||||
"PKIX.EmailProtection" (most likely for use with S/MIME),
|
||||
"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and
|
||||
"PKIX.TimeStamping". You can call "add_ex_constraints" any number of
|
||||
times - each new OID will be added to the list to include in the
|
||||
certificate.
|
||||
|
||||
Lastly, you can add any X.509v3 extensions in the `extensions` member, which is
|
||||
useful if you want to encode a custom extension, or encode an extension in a way
|
||||
differently from how Botan defaults.
|
||||
|
||||
OCSP Requests
|
||||
----------------------------------------
|
||||
|
||||
A client makes an OCSP request to what is termed an 'OCSP responder'. This
|
||||
responder returns a signed response attesting that the certificate in question
|
||||
has not been revoked. The most recent OCSP specification is as of this
|
||||
writing :rfc:`6960`.
|
||||
|
||||
Normally OCSP validation happens automatically as part of X.509 certificate
|
||||
validation, as long as OCSP is enabled (by setting a non-zero ``ocsp_timeout``
|
||||
in the call to ``x509_path_validate``, or for TLS by implementing the related
|
||||
``tls_verify_cert_chain_ocsp_timeout`` callback and returning a non-zero value
|
||||
from that). So most applications should not need to directly manipulate OCSP
|
||||
request and response objects.
|
||||
|
||||
For those that do, the primary ocsp interface is in ``ocsp.h``. First a request
|
||||
must be formed, using information contained in the subject certificate and in
|
||||
the subject's issuing certificate.
|
||||
|
||||
.. cpp:class:: OCSP::Request
|
||||
|
||||
.. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \
|
||||
const BigInt& subject_serial)
|
||||
|
||||
Create a new OCSP request
|
||||
|
||||
.. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \
|
||||
const X509_Certificate& subject_cert)
|
||||
|
||||
Variant of the above, using serial number from ``subject_cert``.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> BER_encode() const
|
||||
|
||||
Encode the current OCSP request as a binary string.
|
||||
|
||||
.. cpp:function:: std::string base64_encode() const
|
||||
|
||||
Encode the current OCSP request as a base64 string.
|
||||
|
||||
Then the response is parsed and validated, and if valid, can be consulted
|
||||
for certificate status information.
|
||||
|
||||
.. cpp:class:: OCSP::Response
|
||||
|
||||
.. cpp:function:: OCSP::Response(const uint8_t response_bits[], size_t response_bits_len)
|
||||
|
||||
Attempts to parse ``response_bits`` as an OCSP response. Throws an
|
||||
exception if parsing fails. Note that this does not verify that the OCSP
|
||||
response is valid (ie that the signature is correct), merely that the
|
||||
ASN.1 structure matches an OCSP response.
|
||||
|
||||
.. cpp:function:: Certificate_Status_Code check_signature( \
|
||||
const std::vector<Certificate_Store*>& trust_roots, \
|
||||
const std::vector<X509_Certificate>& cert_path = const std::vector<X509_Certificate>()) const
|
||||
|
||||
Find the issuing certificate of the OCSP response, and check the signature.
|
||||
|
||||
If possible, pass the full certificate path being validated in
|
||||
the optional ``cert_path`` argument: this additional information
|
||||
helps locate the OCSP signer's certificate in some cases. If this
|
||||
does not return ``Certificate_Status_Code::OCSP_SIGNATURE_OK``,
|
||||
then the request must not be be used further.
|
||||
|
||||
.. cpp:function:: Certificate_Status_Code verify_signature(const X509_Certificate& issuing_cert) const
|
||||
|
||||
If the certificate that issued the OCSP response is already known (eg,
|
||||
because in some specific application all the OCSP responses will always
|
||||
be signed by a single trusted issuer whose cert is baked into the code)
|
||||
this provides an alternate version of `check_signature`.
|
||||
|
||||
.. cpp:function:: Certificate_Status_Code status_for(const X509_Certificate& issuer, \
|
||||
const X509_Certificate& subject, \
|
||||
std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const
|
||||
|
||||
Assuming the signature is valid, returns the status for the subject certificate.
|
||||
Make sure to get the ordering of the issuer and subject certificates correct.
|
||||
|
||||
The ``ref_time`` is normally just the system clock, but can be used if
|
||||
validation against some other reference time is desired (such as for
|
||||
testing, to verify an old previously valid OCSP response, or to use an
|
||||
alternate time source such as the Roughtime protocol instead of the local
|
||||
client system clock).
|
||||
|
||||
.. cpp:function:: const X509_Time& produced_at() const
|
||||
|
||||
Return the time this OCSP response was (claimed to be) produced at.
|
||||
|
||||
.. cpp:function:: const X509_DN& signer_name() const
|
||||
|
||||
Return the distinguished name of the signer. This is used to help
|
||||
find the issuing certificate.
|
||||
|
||||
This field is optional in OCSP responses, and may not be set.
|
||||
|
||||
.. cpp:function:: const std::vector<uint8_t>& signer_key_hash() const
|
||||
|
||||
Return the SHA-1 hash of the public key of the signer. This is used to
|
||||
help find the issuing certificate. The ``Certificate_Store`` API
|
||||
``find_cert_by_pubkey_sha1`` can search on this value.
|
||||
|
||||
This field is optional in OCSP responses, and may not be set.
|
||||
|
||||
.. cpp:function:: const std::vector<uint8_t>& raw_bits() const
|
||||
|
||||
Return the entire raw ASN.1 blob (for debugging or specialized decoding needs)
|
||||
|
||||
One common way of making OCSP requests is via HTTP, see :rfc:`2560`
|
||||
Appendix A for details. A basic implementation of this is the function
|
||||
``online_check``, which is available as long as the ``http_util`` module
|
||||
was compiled in; check by testing for the macro ``BOTAN_HAS_HTTP_UTIL``.
|
||||
|
||||
.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \
|
||||
const BigInt& subject_serial, \
|
||||
const std::string& ocsp_responder, \
|
||||
const Certificate_Store* trusted_roots)
|
||||
|
||||
Assemble a OCSP request for serial number ``subject_serial`` and attempt to request
|
||||
it to responder at URI ``ocsp_responder`` over a new HTTP socket, parses and returns
|
||||
the response. If trusted_roots is not null, then the response is additionally
|
||||
validated using OCSP response API ``check_signature``. Otherwise, this call must be
|
||||
performed later by the application.
|
||||
|
||||
.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \
|
||||
const X509_Certificate& subject, \
|
||||
const Certificate_Store* trusted_roots)
|
||||
|
||||
Variant of the above but uses serial number and OCSP responder URI from ``subject``.
|
@ -1,62 +0,0 @@
|
||||
ZFEC Forward Error Correction
|
||||
===============================
|
||||
|
||||
.. versionadded:: 3.0.0
|
||||
|
||||
The ``ZFEC`` class provides forward error correction compatible
|
||||
with the `zfec <https://github.com/tahoe-lafs/zfec>`_ library.
|
||||
|
||||
Forward error correction takes an input and creates multiple "shares",
|
||||
such that any ``K`` of ``N`` shares is sufficient to recover the
|
||||
entire original input.
|
||||
|
||||
.. note::
|
||||
Specific to the ZFEC format, the first ``K`` generated shares are
|
||||
identical to the original input data, followed by ``N-K`` shares of
|
||||
error correcting code. This is very different from threshold secret
|
||||
sharing, where having fewer than ``K`` shares gives no information
|
||||
about the original input.
|
||||
|
||||
.. warning::
|
||||
If a corrupted share is provided to the decoding algorithm, the
|
||||
resulting decoding will be invalid. It is recommended to protect
|
||||
shares using a technique such as a MAC or public key signature, if
|
||||
corruption is likely in your application.
|
||||
|
||||
``ZFEC`` requires that the input length be exactly divisible by ``K``;
|
||||
if needed define a padding scheme to pad your input to the necessary
|
||||
size.
|
||||
|
||||
An example application that adds padding and a hash checksum is available
|
||||
in ``src/cli/zfec.cpp`` and invokable using ``botan fec_encode`` and
|
||||
``botan fec_decode``.
|
||||
|
||||
.. cpp:class:: ZFEC
|
||||
|
||||
.. cpp:function:: ZFEC(size_t k, size_t n)
|
||||
|
||||
Set up for encoding or decoding using parameters ``k`` and ``n``.
|
||||
Both must be less than 256, and ``k`` must be less than ``n``.
|
||||
|
||||
.. cpp:function:: void encode_shares(const std::vector<const uint8_t*>& shares, \
|
||||
size_t share_size, \
|
||||
std::function<void (size_t, const uint8_t[], size_t)> output_cb) const
|
||||
|
||||
Encode ``K`` shares in ``shares`` each of length ``share_size`` into ``N``
|
||||
shares, also each of length ``share_size``. The ``output_cb`` function will
|
||||
be called once for each output share (in some unspecified and possibly
|
||||
non-deterministic order).
|
||||
|
||||
The parameters to ``output_cb`` are: the share being output, the share
|
||||
contents, and the length of the encoded share (which will always be
|
||||
equal to ``share_size``).
|
||||
|
||||
.. cpp:function:: void decode_shares(const std::map<size_t, const uint8_t*>& shares, \
|
||||
size_t share_size, \
|
||||
std::function<void (size_t, const uint8_t[], size_t)> output_cb) const
|
||||
|
||||
Decode some set of shares into the original input. Each share is
|
||||
of ``share_size`` bytes. The shares are identified by a small
|
||||
integer (between 0 and 255).
|
||||
|
||||
The parameters to ``output_cb`` are similar to that of ``encode_shares``.
|
@ -1,106 +0,0 @@
|
||||
Alastair Houghton
|
||||
Alexander Bluhm (genua GmbH)
|
||||
Alex Gaynor
|
||||
Alf-André Walla
|
||||
Allan L. Bazinet
|
||||
Alon Bar-Lev
|
||||
Andrew Moon
|
||||
Antonio Coratelli
|
||||
Atanas Filyanov
|
||||
Baruch Burstein
|
||||
Bhaskar Biswas
|
||||
Bi11
|
||||
Bogdan Gusiev
|
||||
Chris Desjardins
|
||||
Christian Mainka (Hackmanit GmbH)
|
||||
Christopher Bläsius
|
||||
Christoph Ludwig
|
||||
cryptosource GmbH
|
||||
cynecx
|
||||
Dan Brown
|
||||
Daniel Neus (Rohde & Schwarz Cybersecurity)
|
||||
Daniel Seither (Kullo GmbH)
|
||||
Daniel Wyatt
|
||||
Elektrobit Automotive GmbH
|
||||
Eric Cornelius
|
||||
Erwan Chaussy
|
||||
etcimon
|
||||
Evgeny Pokhilko
|
||||
Fabian Weissberg
|
||||
Falko Strenzke (cryptosource GmbH)
|
||||
Felix Yan
|
||||
FlexSecure GmbH
|
||||
Florent Le Coz
|
||||
Francis Dupont
|
||||
Frank Schoenmann
|
||||
Google Inc
|
||||
Gustavo Serra Scalet
|
||||
guywithcrookedface
|
||||
Hannes Rantzsch
|
||||
Harry Reimann
|
||||
Hegedüs Márton Csaba
|
||||
Hubert Bugaj
|
||||
ilovezfs
|
||||
J08nY
|
||||
Jack Lloyd
|
||||
Jeffrey Walton
|
||||
Joel Low
|
||||
joerg
|
||||
Jose Luis Pereira (Fyde Inc.)
|
||||
Juraj Somorovsky (Hackmanit GmbH)
|
||||
Justin Karneges
|
||||
Kai Michaelis (Rohde & Schwarz Cybersecurity)
|
||||
Kirill A. Korinsky
|
||||
Konstantinos Kolelis
|
||||
Krzysztof Kwiatkowski
|
||||
Lauri Nurmi
|
||||
Luca Piccarreta
|
||||
Manuel Glaser (Rohde & Schwarz Cybersecurity)
|
||||
Manuel Hartl
|
||||
Marcus Brinkmann
|
||||
Markus Wanner
|
||||
Martin Doering
|
||||
Matej Kenda (TopIT d.o.o.)
|
||||
Mathieu Souchaud
|
||||
Matthew Gregan
|
||||
Matthias Gierlings (Hackmanit GmbH)
|
||||
Matt Johnston
|
||||
Michael Boric (Rohde & Schwarz Cybersecurity)
|
||||
Nathan Hourt
|
||||
neXenio GmbH
|
||||
Nicolas Sendrier
|
||||
Nuno Goncalves
|
||||
Ori Peleg
|
||||
Patrick Sona
|
||||
Patrick Wildt
|
||||
Patrik Fiedler
|
||||
Peter J Jones
|
||||
Philippe Lieser (Rohde & Schwarz Cybersecurity)
|
||||
Philipp Weber (Rohde & Schwarz Cybersecurity)
|
||||
Projet SECRET, INRIA, Rocquencourt
|
||||
René Korthaus (Rohde & Schwarz Cybersecurity)
|
||||
René Meusel
|
||||
Ribose Inc
|
||||
Robert Dailey
|
||||
Ryuhei Mori
|
||||
schregger
|
||||
Sergii Cherkavskyi
|
||||
seu
|
||||
Shlomi Fish
|
||||
Simon Cogliani
|
||||
Simon Warta (Kullo GmbH)
|
||||
slaviber
|
||||
souch
|
||||
t0b3
|
||||
tcely
|
||||
Technische Universitat Darmstadt
|
||||
Tim Oesterreich
|
||||
Tobias @neverhub
|
||||
Tomasz Frydrych
|
||||
Uri Blumenthal
|
||||
Vaclav Ovsik
|
||||
Volker Aßmann
|
||||
Yuri
|
||||
Yves Jerschow
|
||||
Zoltan Gyarmati
|
||||
0xdefaced
|
File diff suppressed because it is too large
Load Diff
@ -1,441 +0,0 @@
|
||||
Command Line Interface
|
||||
========================================
|
||||
.. highlight:: sh
|
||||
|
||||
Outline
|
||||
------------
|
||||
|
||||
The ``botan`` program is a command line tool for using a broad variety
|
||||
of functions of the Botan library in the shell.
|
||||
|
||||
All commands follow the syntax ``botan <command> <command-options>``.
|
||||
|
||||
If ``botan`` is run with an unknown command, or without any command, or with the
|
||||
``--help`` option, all available commands will be printed. If a particular
|
||||
command is run with the ``--help`` option (like ``botan <command> --help``)
|
||||
some information about the usage of the command is printed.
|
||||
|
||||
Starting in version 2.9, commands that take a passphrase (such as
|
||||
``gen_bcrypt`` or ``pkcs8``) will also accept the literal ``-`` to mean
|
||||
ask for the passphrase on the terminal. If supported by the operating
|
||||
system, echo will be disabled while reading the passphrase.
|
||||
|
||||
Most arguments that take a path to a file will also accept the literal ``-``
|
||||
to mean the file content should be read from STDIN instead.
|
||||
|
||||
All options for the command line are displayed in the summary line,
|
||||
and in the help output. All options are, as the name suggests,
|
||||
optional, and the default values are shown. For example ``hash file``
|
||||
prints the SHA-256 of the file encoded as hex, while
|
||||
``hash --format=base64 --algo=SHA-384 file`` prints the base64 encoded
|
||||
SHA-384 hash of the same file.
|
||||
|
||||
Hash Function
|
||||
----------------
|
||||
``hash --algo=SHA-256 --buf-size=4096 --no-fsname --format=hex *files``
|
||||
Compute the *algo* digest over the data in any number of *files*. If
|
||||
no files are listed on the command line, the input source defaults
|
||||
to standard input. Unless the ``--no-fsname`` option is given, the
|
||||
filename is printed alongside the hash, in the style of tools such
|
||||
as ``sha256sum``.
|
||||
|
||||
Password Hash
|
||||
----------------
|
||||
``gen_argon2 --mem=65536 --p=1 --t=1 password``
|
||||
Calculate the Argon2 password digest of *password*. *mem* is the amount of
|
||||
memory to use in Kb, *p* the parallelization parameter and *t* the number of
|
||||
iterations to use.
|
||||
|
||||
``check_argon2 password hash``
|
||||
Checks if the Argon2 hash of the passed *password* equals the passed *hash* value.
|
||||
|
||||
``gen_bcrypt --work-factor=12 password``
|
||||
Calculate the bcrypt password digest of *password*. *work-factor* is an
|
||||
integer between 4 and 18. A higher *work-factor* value results in a
|
||||
more expensive hash calculation.
|
||||
|
||||
``check_bcrypt password hash``
|
||||
Checks if the bcrypt hash of the passed *password* equals the passed *hash* value.
|
||||
|
||||
``pbkdf_tune --algo=Scrypt --max-mem=256 --output-len=32 --check *times``
|
||||
Tunes the PBKDF algorithm specified with ``--algo=`` for the given *times*.
|
||||
|
||||
HMAC
|
||||
----------------
|
||||
``hmac --hash=SHA-256 --buf-size=4096 --no-fsname key files``
|
||||
Compute the HMAC tag with the cryptographic hash function *hash*
|
||||
using the key in file *key* over the data in *files*. *files*
|
||||
defaults to STDIN. Unless the ``--no-fsname`` option is given, the
|
||||
filename is printed alongside the HMAC value.
|
||||
|
||||
Encryption
|
||||
----------------
|
||||
``cipher --buf-size=4096 --decrypt --cipher= --key= --nonce= --ad=``
|
||||
|
||||
Encrypt a given file with the specified *cipher*, eg "AES-256/GCM".
|
||||
If ``--decrypt`` is provided the file is decrypted instead.
|
||||
|
||||
Public Key Cryptography
|
||||
-------------------------------------
|
||||
``keygen --algo=RSA --params= --passphrase= --cipher= --pbkdf= --pbkdf-ms=300 --provider= --der-out``
|
||||
Generate a PKCS #8 *algo* private key. If *der-out* is passed, the pair is BER
|
||||
encoded. Otherwise, PEM encoding is used. To protect the PKCS #8 formatted
|
||||
key, it is recommended to encrypt it with a provided *passphrase*.
|
||||
|
||||
If a passphrase is used, *cipher* specifies the name of the desired encryption
|
||||
algorithm (such as "AES-256/CBC", or leave empty to use a default), and
|
||||
*pbkdf* can be used to specify the password hashing mechanism (either a hash
|
||||
such as "SHA-256" to select PBKDF2, or "Scrypt").
|
||||
|
||||
The cipher mode must have an object identifier defined, this allows use of
|
||||
ciphers such as AES, Twofish, Serpent, and SM4. Ciphers in CBC, GCM, and SIV
|
||||
modes are supported. However most other implementations support only AES or
|
||||
3DES in CBC mode.
|
||||
|
||||
If encryption is used, the parameter *pbkdf-ms* controls how long the password
|
||||
hashing function will run to derive the encryption key from the passed
|
||||
*passphrase*.
|
||||
|
||||
Algorithm specific parameters, as the desired bit length of an RSA key, can be
|
||||
passed with *params*.
|
||||
|
||||
- For RSA *params* specifies the bit length of the RSA modulus. It defaults to 3072.
|
||||
- For DH *params* specifies the DH parameters. It defaults to modp/ietf/2048.
|
||||
- For DSA *params* specifies the DSA parameters. It defaults to dsa/botan/2048.
|
||||
- For EC algorithms *params* specifies the elliptic curve. It defaults to secp256r1.
|
||||
|
||||
``pkcs8 --pass-in= --pub-out --der-out --pass-out= --cipher= --pbkdf= --pbkdf-ms=300 key``
|
||||
|
||||
Open a PKCS #8 formatted key at *key*. If *key* is encrypted, the passphrase
|
||||
must be passed as *pass-in*. It is possible to (re)encrypt the read key with
|
||||
the passphrase passed as *pass-out*. The parameters *cipher*, *pbkdf*, and
|
||||
*pbkdf-ms* work similarly to ``keygen``.
|
||||
|
||||
``sign --der-format --passphrase= --hash=SHA-256 --padding= --provider= key file``
|
||||
|
||||
Sign the data in *file* using the PKCS #8 private key *key* and cryptographic
|
||||
hash *hash*. If *key* is encrypted, the used passphrase must be passed as
|
||||
*pass-in*.
|
||||
|
||||
The *padding* option can be used to control padding for algorithms that have
|
||||
divergent methods; this mostly applies to RSA. For RSA, if the option is not
|
||||
specified PSS signatures are used. You can select generating a PKCS #1 v1.5
|
||||
formatted signature instead by providing ``--padding=PKCS1v15``.
|
||||
|
||||
For ECDSA and DSA, the option ``--der-format`` outputs the signature as an
|
||||
ASN.1 encoded blob. Some other tools (including ``openssl``) default to this
|
||||
format. This option does not make sense for other algorithms such as RSA.
|
||||
|
||||
The signature is formatted for your screen using base64.
|
||||
|
||||
``verify --der-format --hash=SHA-256 --padding= pubkey file signature``
|
||||
Verify the authenticity of the data in *file* with the provided signature
|
||||
*signature* and the public key *pubkey*. Similarly to the signing process,
|
||||
*padding* specifies the padding scheme and *hash* the cryptographic hash
|
||||
function to use.
|
||||
|
||||
``gen_dl_group --pbits=1024 --qbits=0 --seed= --type=subgroup``
|
||||
Generate ANSI X9.42 encoded Diffie-Hellman group parameters.
|
||||
|
||||
- If *type=subgroup* is passed, the size of the prime subgroup q is sampled
|
||||
as a prime of *qbits* length and p is *pbits* long. If *qbits* is not
|
||||
passed, its length is estimated from *pbits* as described in RFC 3766.
|
||||
- If *type=strong* is passed, p is sampled as a safe prime with length
|
||||
*pbits* and the prime subgroup has size q with *pbits*-1 length.
|
||||
- If *type=dsa* is used, p and q are generated by the algorithm specified in
|
||||
FIPS 186-4. If the ``--seed`` parameter is used, it allows to select the
|
||||
seed value, instead of one being randomly generated. If the seed does not
|
||||
in fact generate a valid DSA group, the command will fail.
|
||||
|
||||
``dl_group_info --pem name``
|
||||
Print raw Diffie-Hellman parameters (p,g) of the standardized DH group
|
||||
*name*. If *pem* is set, the X9.42 encoded group is printed.
|
||||
|
||||
``ec_group_info --pem name``
|
||||
Print raw elliptic curve domain parameters of the standardized curve *name*. If
|
||||
*pem* is set, the encoded domain is printed.
|
||||
|
||||
``pk_encrypt --aead=AES-256/GCM rsa_pubkey datafile``
|
||||
Encrypts ``datafile`` using the specified AEAD algorithm, under a key protected
|
||||
by the specified RSA public key.
|
||||
|
||||
``pk_decrypt rsa_privkey datafile``
|
||||
Decrypts a file encrypted with ``pk_encrypt``. If the key is encrypted using a
|
||||
password, it will be prompted for on the terminal.
|
||||
|
||||
``fingerprint --no-fsname --algo=SHA-256 *keys``
|
||||
Calculate the public key fingerprint of the *keys*.
|
||||
|
||||
``pk_workfactor --type=rsa bits``
|
||||
Provide an estimate of the strength of a public key based on it's size.
|
||||
``--type=`` can be "rsa", "dl" or "dl_exp".
|
||||
|
||||
X.509
|
||||
----------------------------------------------
|
||||
|
||||
``gen_pkcs10 key CN --country= --organization= --ca --path-limit=1 --email= --dns= --ext-ku= --key-pass= --hash=SHA-256 --emsa=``
|
||||
Generate a PKCS #10 certificate signing request (CSR) using the passed PKCS #8
|
||||
private key *key*. If the private key is encrypted, the decryption passphrase
|
||||
*key-pass* has to be passed.*emsa* specifies the padding scheme to be used
|
||||
when calculating the signature.
|
||||
|
||||
- For RSA keys EMSA4 (RSA-PSS) is the default scheme.
|
||||
- For ECDSA, DSA, ECGDSA, ECKCDSA and GOST-34.10 keys *emsa* defaults to EMSA1.
|
||||
|
||||
``gen_self_signed key CN --country= --dns= --organization= --email= --path-limit=1 --days=365 --key-pass= --ca --hash=SHA-256 --emsa= --der``
|
||||
Generate a self signed X.509 certificate using the PKCS #8 private key
|
||||
*key*. If the private key is encrypted, the decryption passphrase *key-pass*
|
||||
has to be passed. If *ca* is passed, the certificate is marked for certificate
|
||||
authority (CA) usage. *emsa* specifies the padding scheme to be used when
|
||||
calculating the signature.
|
||||
|
||||
- For RSA keys EMSA4 (RSA-PSS) is the default scheme.
|
||||
- For ECDSA, DSA, ECGDSA, ECKCDSA and GOST-34.10 keys *emsa* defaults to EMSA1.
|
||||
|
||||
``sign_cert --ca-key-pass= --hash=SHA-256 --duration=365 --emsa= ca_cert ca_key pkcs10_req``
|
||||
Create a CA signed X.509 certificate from the information contained in the
|
||||
PKCS #10 CSR *pkcs10_req*. The CA certificate is passed as *ca_cert* and the
|
||||
respective PKCS #8 private key as *ca_key*. If the private key is encrypted,
|
||||
the decryption passphrase *ca-key-pass* has to be passed. The created
|
||||
certificate has a validity period of *duration* days. *emsa* specifies the
|
||||
padding scheme to be used when calculating the signature. *emsa* defaults to
|
||||
the padding scheme used in the CA certificate.
|
||||
|
||||
``ocsp_check --timeout=3000 subject issuer``
|
||||
Verify an X.509 certificate against the issuers OCSP responder. Pass the
|
||||
certificate to validate as *subject* and the CA certificate as *issuer*.
|
||||
|
||||
``cert_info --fingerprint file``
|
||||
Parse X.509 PEM certificate and display data fields. If ``--fingerprint`` is
|
||||
used, the certificate's fingerprint is also printed.
|
||||
|
||||
``cert_verify subject *ca_certs``
|
||||
Verify if the provided X.509 certificate *subject* can be successfully
|
||||
validated. The list of trusted CA certificates is passed with *ca_certs*,
|
||||
which is a list of one or more certificates.
|
||||
|
||||
``trust_roots --dn --dn-only --display``
|
||||
List the certificates in the system trust store.
|
||||
|
||||
TLS Server/Client
|
||||
-----------------------
|
||||
|
||||
The ``--policy=`` argument of the TLS commands specifies the TLS policy to use.
|
||||
The policy can be any of the strings "default", "suiteb_128", "suiteb_192",
|
||||
"bsi", "strict", or "all" to denote built-in policies, or it can name a file
|
||||
from which a policy description will be read.
|
||||
|
||||
``tls_ciphers --policy=default --version=tls1.2``
|
||||
Prints the list of ciphersuites that will be offered under a particular
|
||||
policy/version.
|
||||
|
||||
``tls_client host --port=443 --print-certs --policy=default --tls1.0 --tls1.1 --tls1.2 --skip-system-cert-store --trusted-cas= --session-db= --session-db-pass= --next-protocols= --type=tcp --client-cert= --client-cert-key=``
|
||||
Implements a testing TLS client, which connects to *host* via TCP or UDP on
|
||||
port *port*. The TLS version can be set with the flags *tls1.0*, *tls1.1* and
|
||||
*tls1.2* of which the lowest specified version is automatically chosen. If
|
||||
none of the TLS version flags is set, the latest supported version is
|
||||
chosen. The client honors the TLS policy specified with *policy* and
|
||||
prints all certificates in the chain, if *print-certs* is passed.
|
||||
*next-protocols* is a comma separated list and specifies the protocols to
|
||||
advertise with Application-Layer Protocol Negotiation (ALPN).
|
||||
Pass a path to a client certificate PEM and unencrypted PKCS8 encoded private
|
||||
key if client authentication is required.
|
||||
|
||||
``tls_server cert key --port=443 --type=tcp --policy=default --dump-traces= --max-clients=0 --socket-id=0``
|
||||
Implements a testing TLS server, which allows TLS clients to connect and which
|
||||
echos any data that is sent to it. Binds to either TCP or UDP on port
|
||||
*port*. The server uses the certificate *cert* and the respective PKCS #8
|
||||
private key *key*. The server honors the TLS policy specified with *policy*.
|
||||
*socket-id* is only available on FreeBSD and sets the *so_user_cookie* value
|
||||
of the used socket.
|
||||
|
||||
``tls_http_server cert key --port=443 --policy=default --threads=0 --max-clients=0 --session-db --session-db-pass=``
|
||||
Only available if Boost.Asio support was enabled. Provides a simple HTTP server
|
||||
which replies to all requests with an informational text output. The server
|
||||
honors the TLS policy specified with *policy*.
|
||||
|
||||
``tls_proxy listen_port target_host target_port server_cert server_key--policy=default --threads=0 --max-clients=0 --session-db= --session-db-pass=``
|
||||
Only available if Boost.Asio support was enabled. Listens on a port and
|
||||
forwards all connects to a target server specified at
|
||||
``target_host`` and ``target_port``.
|
||||
|
||||
``tls_client_hello --hex input``
|
||||
Parse and print a TLS client hello message.
|
||||
|
||||
Number Theory
|
||||
-----------------------
|
||||
``is_prime --prob=56 n``
|
||||
Test if the integer *n* is composite or prime with a Miller-Rabin primality test with *(prob+2)/2* iterations.
|
||||
|
||||
``factor n``
|
||||
Factor the integer *n* using a combination of trial division by small primes, and Pollard's Rho algorithm.
|
||||
It can in reasonable time factor integers up to 110 bits or so.
|
||||
|
||||
``gen_prime --count=1 bits``
|
||||
Samples *count* primes with a length of *bits* bits.
|
||||
|
||||
``mod_inverse n mod``
|
||||
Calculates a modular inverse.
|
||||
|
||||
PSK Database
|
||||
--------------------
|
||||
|
||||
The PSK database commands are only available if sqlite3 support was compiled in.
|
||||
|
||||
``psk_set db db_key name psk``
|
||||
Using the PSK database named db and encrypting under the (hex) key ``db_key``,
|
||||
save the provided psk (also hex) under ``name``::
|
||||
|
||||
$ botan psk_set psk.db deadba55 bunny f00fee
|
||||
|
||||
``psk_get db db_key name``
|
||||
Get back a value saved with ``psk_set``::
|
||||
|
||||
$ botan psk_get psk.db deadba55 bunny
|
||||
f00fee
|
||||
|
||||
``psk_list db db_key``
|
||||
List all values saved to the database under the given key::
|
||||
|
||||
$ botan psk_list psk.db deadba55
|
||||
bunny
|
||||
|
||||
Secret Sharing
|
||||
------------------
|
||||
|
||||
Split a file into several shares.
|
||||
|
||||
``tss_split M N data_file --id= --share-prefix=share --share-suffix=tss --hash=SHA-256``
|
||||
Split a file into ``N`` pieces any ``M`` of which suffices to
|
||||
recover the original input. The ID allows specifying a unique key ID
|
||||
which may be up to 16 bytes long, this ensures that shares can be
|
||||
uniquely matched. If not specified a random 16 byte value is
|
||||
used. A checksum can be appended to the data to help verify correct
|
||||
recovery, this can be disabled using ``--hash=None``.
|
||||
|
||||
``tss_recover *shares``
|
||||
Recover some data split by ``tss_split``. If insufficient number of
|
||||
shares are provided an error is printed.
|
||||
|
||||
Data Encoding/Decoding
|
||||
------------------------
|
||||
|
||||
``base32_dec file``
|
||||
Decode *file* to Base32.
|
||||
|
||||
``base32_enc file``
|
||||
Encode Base32 encoded *file*.
|
||||
|
||||
``base58_enc --check file``
|
||||
Encode *file* to Base58. If ``--check`` is provided Base58Check is used.
|
||||
|
||||
``base58_dec --check file``
|
||||
Decode Base58 encoded *file*. If ``--check`` is provided Base58Check is used.
|
||||
|
||||
``base64_dec file``
|
||||
Decode *file* to Base64.
|
||||
|
||||
``base64_enc file``
|
||||
Encode Base64 encoded *file*.
|
||||
|
||||
``hex_dec file``
|
||||
Decode *file* to Hex.
|
||||
|
||||
``hex_enc file``
|
||||
Encode Hex encoded *file*.
|
||||
|
||||
Forward Error Correction
|
||||
------------------------
|
||||
|
||||
``fec_encode --suffix=fec --prefix= --output-dir= k n input``
|
||||
Split a given ``input`` file into ``n`` shares where ``k`` shares are required
|
||||
to recreate the original file. The output shares a written to files with the
|
||||
file extension specified in ``--suffix`` and either the original file name or
|
||||
the one specified in ``--prefix``. The output directory is either equal to the
|
||||
input file's directory or the one specified in ``--output-dir``.
|
||||
|
||||
``fec_decode *shares``
|
||||
If given enough shares, this will output the original input file's content to
|
||||
stdout. Otherwise an error is printed on stderr.
|
||||
|
||||
``fec_info share``
|
||||
Given a single share this will print information about the share.
|
||||
For instance: ``FEC share 4/4 with 3 needed for recovery``
|
||||
|
||||
Miscellaneous Commands
|
||||
-------------------------------------
|
||||
``version --full``
|
||||
Print the version number. If option ``--full`` is provided,
|
||||
additional details are printed.
|
||||
|
||||
``has_command cmd``
|
||||
Test if the command *cmd* is available.
|
||||
|
||||
``config info_type``
|
||||
Prints build information, useful for applications which want to
|
||||
build against the library. The ``info_type`` argument can be any of
|
||||
``prefix``, ``cflags``, ``ldflags``, or ``libs``. This is
|
||||
similar to information provided by the ``pkg-config`` tool.
|
||||
|
||||
``cpuid``
|
||||
List available processor flags (AES-NI, SIMD extensions, ...).
|
||||
|
||||
``cpu_clock --test-duration=500``
|
||||
Estimate the speed of the CPU cycle counter.
|
||||
|
||||
``asn1print --skip-context-specific --print-limit=4096 --bin-limit=2048 --max-depth=64 --pem file```
|
||||
Decode and print *file* with ASN.1 Basic Encoding Rules (BER). If flag ``--pem`` is
|
||||
used, or the filename ends in ``.pem``, then PEM encoding is assumed. Otherwise
|
||||
the input is assumed to be binary DER/BER.
|
||||
|
||||
``http_get --redirects=1 --timeout=3000 url``
|
||||
Retrieve resource from the passed http *url*.
|
||||
|
||||
``speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos``
|
||||
Measures the speed of the passed *algos*. If no *algos* are passed all
|
||||
available speed tests are executed. *msec* (in milliseconds) sets the period
|
||||
of measurement for each algorithm. The *buf-size* option allows testing the
|
||||
same algorithm on one or more input sizes, for example
|
||||
``speed --buf-size=136,1500 AES-128/GCM`` tests the performance of GCM for
|
||||
small and large packet sizes.
|
||||
*format* can be "default", "table" or "json".
|
||||
|
||||
``timing_test test_type --test-data-file= --test-data-dir=src/tests/data/timing --warmup-runs=1000 --measurement-runs=10000``
|
||||
Run various timing side channel tests.
|
||||
|
||||
``rng --format=hex --system --rdrand --auto --entropy --drbg --drbg-seed= *bytes``
|
||||
Sample *bytes* random bytes from the specified random number generator. If
|
||||
*system* is set, the system RNG is used. If *rdrand* is set, the hardware
|
||||
RDRAND instruction is used. If *auto* is set, AutoSeeded_RNG is used, seeded
|
||||
with the system RNG if available or the global entropy source otherwise. If
|
||||
*entropy* is set, AutoSeeded_RNG is used, seeded with the global entropy
|
||||
source. If *drbg* is set, HMAC_DRBG is used seeded with *drbg-seed*.
|
||||
|
||||
``entropy --truncate-at=128 source``
|
||||
Sample a raw entropy source.
|
||||
|
||||
``cc_encrypt CC passphrase --tweak=``
|
||||
Encrypt the passed valid credit card number *CC* using FPE encryption and the
|
||||
passphrase *passphrase*. The key is derived from the passphrase using PBKDF2
|
||||
with SHA256. Due to the nature of FPE, the ciphertext is also a credit card
|
||||
number with a valid checksum. *tweak* is public and parameterizes the
|
||||
encryption function.
|
||||
|
||||
``cc_decrypt CC passphrase --tweak=``
|
||||
Decrypt the passed valid ciphertext *CC* using FPE decryption with
|
||||
the passphrase *passphrase* and the tweak *tweak*.
|
||||
|
||||
``roughtime_check --raw-time chain-file``
|
||||
Parse and validate a Roughtime chain file.
|
||||
|
||||
``roughtime --raw-time --chain-file=roughtime-chain --max-chain-size=128 --check-local-clock=60 --host= --pubkey= --servers-file=``
|
||||
Retrieve time from a Roughtime server and store it in a chain file.
|
||||
|
||||
``uuid``
|
||||
Generate and print a random UUID.
|
||||
|
||||
``compress --type=gzip --level=6 --buf-size=8192 file``
|
||||
Compress a given file.
|
||||
|
||||
``decompress --buf-size=8192 file``
|
||||
Decompress a given compressed archive.
|
@ -1,27 +0,0 @@
|
||||
|
||||
Contents
|
||||
========================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
index
|
||||
goals
|
||||
support
|
||||
building
|
||||
sem_ver
|
||||
migration_guide
|
||||
api_ref/contents
|
||||
cli
|
||||
deprecated
|
||||
roadmap
|
||||
credits
|
||||
abi
|
||||
packaging
|
||||
security
|
||||
side_channels
|
||||
dev_ref/contents
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
old_news
|
@ -1,179 +0,0 @@
|
||||
|
||||
Credits
|
||||
========================================
|
||||
|
||||
This is at least a partial credits-file of people that have contributed
|
||||
to botan. It is sorted by name and formatted to allow easy grepping
|
||||
and beautification by scripts. The fields are name (N), email (E),
|
||||
web-address (W), PGP key ID and fingerprint (P), description (D),
|
||||
snail-mail address (S), and Bitcoin address (B).
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
N: Alexander Bluhm
|
||||
W: https://www.genua.de/
|
||||
P: 1E3B BEA4 6C20 EA00 2FFC DE4D C5F4 83AD DEE8 6380
|
||||
D: improve support for OpenBSD
|
||||
S: Kirchheim, Germany
|
||||
|
||||
N: Charles Brockman
|
||||
W: http://www.securitygenetics.com/
|
||||
D: documentation editing
|
||||
S: Oregon, USA
|
||||
|
||||
N: Simon Cogliani
|
||||
E: simon.cogliani@tanker.io
|
||||
W: https://www.tanker.io/
|
||||
P: EA73 D0AF 5A81 A61A 8931 C2CA C9AB F2E4 3820 4F25
|
||||
D: Getting keystream of ChaCha
|
||||
S: Paris, France
|
||||
|
||||
N: Martin Doering
|
||||
E: doering@cdc.informatik.tu-darmstadt.de
|
||||
D: GF(p) arithmetic
|
||||
|
||||
N: Olivier de Gaalon
|
||||
D: SQLite encryption codec (src/contrib/sqlite)
|
||||
|
||||
N: Matthias Gierlings
|
||||
E: matthias.gierlings@hackmanit.de
|
||||
W: https://www.hackmanit.de/
|
||||
P: 39E0 D270 19A4 B356 05D0 29AE 1BD3 49CF 744A 02FF
|
||||
D: GMAC, Extended Hash-Based Signatures (XMSS)
|
||||
S: Bochum, Germany
|
||||
|
||||
N: Matthew Gregan
|
||||
D: Binary file I/O support, allocator fixes
|
||||
|
||||
N: Hany Greiss
|
||||
D: Windows porting
|
||||
|
||||
N: Manuel Hartl
|
||||
E: hartl@flexsecure.de
|
||||
W: http://www.flexsecure.de/
|
||||
D: ECDSA, ECDH
|
||||
|
||||
N: Yves Jerschow
|
||||
E: yves.jerschow@uni-duesseldorf.de
|
||||
D: Optimizations for memory load/store and HMAC
|
||||
D: Support for IPv4 addresses in X.509 alternative names
|
||||
S: Germany
|
||||
|
||||
N: Matt Johnston
|
||||
D: Allocator fixes and optimizations, decompressor fixes
|
||||
|
||||
N: Peter J. Jones
|
||||
E: pjones@pmade.org
|
||||
D: Bzip2 compression module
|
||||
S: Colorado, USA
|
||||
|
||||
N: Justin Karneges
|
||||
D: Qt support modules (mutexes and types), X.509 API design
|
||||
|
||||
N: Vojtech Kral
|
||||
E: vojtech@kral.hk
|
||||
D: LZMA compression module
|
||||
S: Czech Republic
|
||||
|
||||
N: Matej Kenda
|
||||
E: matej.kenda@topit.si
|
||||
D: Locking in Algo_Registry for Windows OS
|
||||
S: Slovenia
|
||||
|
||||
N: René Fischer (formerly Korthaus)
|
||||
E: rene.fischer@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
P: C196 FF9D 3DDC A5E7 F98C E745 9AD0 F9FA 587E 74D6
|
||||
D: CI, ECGDSA, ECKCDSA
|
||||
S: Bochum, Germany
|
||||
|
||||
N: Adam Langley
|
||||
E: agl@imperialviolet.org
|
||||
D: Curve25519
|
||||
|
||||
N: Jack Lloyd
|
||||
E: jack@randombit.net
|
||||
W: https://www.randombit.net/
|
||||
P: 3F69 2E64 6D92 3BBE E7AE 9258 5C0F 96E8 4EC1 6D6B
|
||||
B: 1DwxWb2J4vuX4vjsbzaCXW696rZfeamahz
|
||||
D: Original designer/author, maintainer 2001-current
|
||||
S: Vermont, USA
|
||||
|
||||
N: Joel Low
|
||||
D: DLL symbol visibility and Windows DLL support in general
|
||||
D: Threaded_Fork
|
||||
|
||||
N: Christoph Ludwig
|
||||
E: ludwig@fh-worms.de
|
||||
D: GP(p) arithmetic
|
||||
|
||||
N: Vaclav Ovsik
|
||||
E: vaclav.ovsik@i.cz
|
||||
D: Perl XS module (src/contrib/perl-xs)
|
||||
|
||||
N: Luca Piccarreta
|
||||
E: luca.piccarreta@gmail.com
|
||||
D: x86/amd64 assembler, BigInt optimizations, Win32 mutex module
|
||||
S: Italy
|
||||
|
||||
N: Daniel Seither
|
||||
E: post@tiwoc.de
|
||||
D: iOS support, improved Android support, improved MSVC support
|
||||
|
||||
N: Falko Strenzke
|
||||
E: fstrenzke@cryptosource.de
|
||||
W: http://www.cryptosource.de
|
||||
D: McEliece, GF(p) arithmetic, CVC, Shanks-Tonelli algorithm
|
||||
S: Darmstadt, Germany
|
||||
|
||||
N: Simon Warta
|
||||
E: simon@kullo.net
|
||||
W: https://www.kullo.net
|
||||
D: Build system
|
||||
S: Germany
|
||||
|
||||
N: Philipp Weber
|
||||
E: philipp.weber@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
D: KDF1-18033, ECIES
|
||||
S: Saarland, Germany
|
||||
|
||||
N: Daniel Neus
|
||||
E: daniel.neus@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
D: CI, PKCS#11, RdSeed, BSI module policy
|
||||
S: Bochum, Germany
|
||||
|
||||
N: Erwan Chaussy
|
||||
D: Base32, Base64 matching Base32 implementation
|
||||
S: France
|
||||
|
||||
N: Daniel Wyatt (on behalf of Ribose Inc)
|
||||
E: daniel.wyatt@ribose.com
|
||||
W: https://www.ribose.com/
|
||||
D: SM3, Streebog, various minor contributions
|
||||
|
||||
N: Rostyslav Khudolii
|
||||
E: rhudoliy@gmail.com
|
||||
D: SRP6 FFI
|
||||
S: Ukraine/Denmark
|
||||
|
||||
N: René Meusel
|
||||
E: rene.meusel@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
D: CI, TLS 1.3, Kyber, Dilithium, SPHINCS+
|
||||
S: Berlin, Germany
|
||||
|
||||
N: Philippe Lieser
|
||||
E: philippe.lieser@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
D: CI, BSI module policy, various minor contributions
|
||||
S: Saarland, Germany
|
||||
|
||||
N: Fabian Albert
|
||||
E: fabian.albert@rohde-schwarz.com
|
||||
W: https://www.rohde-schwarz.com/cybersecurity
|
||||
D: SPHINCS+
|
||||
S: Bochum, Germany
|
@ -1,134 +0,0 @@
|
||||
Deprecated Features
|
||||
========================
|
||||
|
||||
Certain functionality is deprecated and is likely to be removed in
|
||||
a future major release.
|
||||
|
||||
To help warn users, macros are used to annotate deprecated functions
|
||||
and headers. These warnings are enabled by default, but can be
|
||||
disabled by defining the macro ``BOTAN_NO_DEPRECATED_WARNINGS`` prior
|
||||
to including any Botan headers.
|
||||
|
||||
.. warning::
|
||||
Not all of the functionality which is currently deprecated has an
|
||||
associated warning.
|
||||
|
||||
If you are using something which is currently deprecated and there
|
||||
doesn't seem to be an obvious alternative, contact the developers to
|
||||
explain your use case if you want to make sure your code continues to
|
||||
work.
|
||||
|
||||
Platform Support Deprecations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Support for building for Windows systems prior to Windows 10 is deprecated.
|
||||
|
||||
TLS Protocol Deprecations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following TLS protocol features are deprecated and will be removed
|
||||
in a future major release:
|
||||
|
||||
- Support for point compression in TLS. This is supported in v1.2 but
|
||||
removed in v1.3. For simplicity it will be removed in v1.2 also.
|
||||
|
||||
- All CBC mode ciphersuites. This includes all available 3DES ciphersuites.
|
||||
This implies also removing Encrypt-then-MAC extension.
|
||||
|
||||
- All DHE ciphersuites
|
||||
|
||||
- Support for renegotiation in TLS v1.2
|
||||
|
||||
- All ciphersuites using static RSA key exchange
|
||||
|
||||
- ``Credentials_Manager::psk()`` to provide various TLS-specific keys and
|
||||
secrets, most notably "session-ticket", "dtls-cookie-secret" and the actual
|
||||
TLS PSKs for given identities and hosts. Instead, use the dedicated methods in
|
||||
``Credentials_Manager`` and do not override the ``psk()`` method any longer.
|
||||
|
||||
Deprecated Functionality
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This section lists cryptographic functionality which will be removed
|
||||
in a future major release.
|
||||
|
||||
- Kyber 90s mode is deprecated and will be removed.
|
||||
|
||||
- Currently it is possible to create an EC_Group with cofactor > 1.
|
||||
None of the builtin groups have composite order, and in the future
|
||||
it will be impossible to create composite order EC_Groups.
|
||||
|
||||
- Prior to 2.8.0, SM2 algorithms were implemented as two distinct key
|
||||
types, one used for encryption and the other for signatures. In 2.8,
|
||||
the two types were merged. However it is still possible to refer to
|
||||
SM2 using the split names of "SM2_Enc" or "SM2_Sig". In a future major
|
||||
release this will be removed, and only "SM2" will be recognized.
|
||||
|
||||
- DSA, ECDSA, ECGDSA, ECKCDSA, and GOST-34.10 previously (before Botan 3)
|
||||
required that the hash be named as "EMSA1(HASH_NAME)". This is no longer
|
||||
required. In a future major release, only "HASH_NAME" will be accepted.
|
||||
|
||||
- Block cipher GOST 28147, Noekeon, Lion
|
||||
|
||||
- Hash function GOST 34.11-94, Streebog, MD4
|
||||
|
||||
- GOST 34.10 signature scheme
|
||||
|
||||
- Stream cipher SHAKE (this does not affect SHAKE used as a HashFunction or XOF)
|
||||
|
||||
- The utility functions in cryptobox.h
|
||||
|
||||
- X9.42 KDF
|
||||
|
||||
- The current McEliece implementation (in ``pubkey/mce``) will be
|
||||
replaced by a more modern code-based KEM from the NIST
|
||||
competition. (Probably the "Classic McEliece" submission.)
|
||||
|
||||
- DLIES
|
||||
|
||||
- GCM support for 64-bit tags
|
||||
|
||||
- Weak or rarely used ECC builtin groups including "secp160k1", "secp160r1",
|
||||
"secp160r2", "secp192k1", "secp224k1",
|
||||
"brainpool160r1", "brainpool192r1", "brainpool224r1", "brainpool320r1",
|
||||
"x962_p192v2", "x962_p192v3", "x962_p239v1", "x962_p239v2", "x962_p239v3".
|
||||
|
||||
- All built in MODP groups < 2048 bits
|
||||
|
||||
- Support for explicit ECC curve parameters and ImplicitCA encoded parameters in
|
||||
EC_Group and all users (including X.509 certificates and PKCS#8 private keys).
|
||||
|
||||
- All pre-created DSA groups
|
||||
|
||||
- All support for loading, generating or using RSA keys with a public
|
||||
exponent larger than 2**64-1
|
||||
|
||||
Deprecated Headers
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
PBKDF headers: ``bcrypt_pbkdf.h``, ``pbkdf2.h``, ``pgp_s2k.h``, ``scrypt.h``,
|
||||
and ``argon2.h``: Use the ``PasswordHash`` interface instead.
|
||||
|
||||
Internal implementation headers - seemingly no reason for applications to use:
|
||||
``curve_gfp.h``,
|
||||
``reducer.h``,
|
||||
``tls_algos.h``,
|
||||
``tls_magic.h``
|
||||
|
||||
Utility headers, nominally useful in applications but not a core part of
|
||||
the library API and most are just sufficient for what the library needs
|
||||
to implement other functionality.
|
||||
``compiler.h``,
|
||||
``uuid.h``,
|
||||
|
||||
Other API deprecations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- The ``PBKDF`` class is deprecated in favor of ``PasswordHash`` and
|
||||
``PasswordHashFamily``.
|
||||
|
||||
- The ``Buffered_Computation`` base class. In a future release the
|
||||
class will be removed, and all of member functions instead declared
|
||||
directly on ``MessageAuthenticationCode`` and ``HashFunction``. So
|
||||
this only affects you if you are directly referencing
|
||||
``Botan::Buffered_Computation`` in some way.
|
@ -1,440 +0,0 @@
|
||||
.. _configure_script:
|
||||
|
||||
Understanding configure.py
|
||||
============================
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
Botan's build is handled with a custom Python script, ``configure.py``.
|
||||
This document tries to explain how configure works.
|
||||
|
||||
.. note::
|
||||
You only need to read this if you are modifying the library,
|
||||
or debugging some problem with your build. For how to use it,
|
||||
see :ref:`building`.
|
||||
|
||||
Build Structure
|
||||
--------------------
|
||||
|
||||
Modules are a group of related source and header files, which can be
|
||||
individually enabled or disabled at build time. Modules can depend on
|
||||
other modules; if a dependency is not available then the module itself
|
||||
is also removed from the list. Examples of modules in the existing
|
||||
codebase are ``asn1`` and ``x509``, Since ``x509`` depends on (among
|
||||
other things) ``asn1``, disabling ``asn1`` will also disable ``x509``.
|
||||
|
||||
Most modules define one or more macros, which application code can use
|
||||
to detect the modules presence or absence. The value of each macro is
|
||||
a datestamp, in the form YYYYMMDD which indicates the last time this
|
||||
module changed in a way that would be visible to an application. For
|
||||
example if a class gains a new function, the datestamp should be
|
||||
incremented. That allows applications to detect if the new feature is
|
||||
available.
|
||||
|
||||
What ``configure.py`` does
|
||||
-----------------------------
|
||||
|
||||
First, all command line options are parsed.
|
||||
|
||||
Then all of the files giving information about target CPUs, compilers,
|
||||
etc are parsed and sanity checked.
|
||||
|
||||
In ``calculate_cc_min_version`` the compiler version is detected using
|
||||
the preprocessor.
|
||||
|
||||
Then in ``check_compiler_arch`` the target architecture are detected, again
|
||||
using the preprocessor.
|
||||
|
||||
Now that the target is identified and options have been parsed, the modules to
|
||||
include into the artifact are picked, in ``ModulesChooser``.
|
||||
|
||||
In ``create_template_vars``, a dictionary of variables is created which describe
|
||||
different aspects of the build. These are serialized to
|
||||
``build/build_config.json``.
|
||||
|
||||
Up until this point no changes have been made on disk. This occurs in
|
||||
``do_io_for_build``. Build output directories are created, and header files are
|
||||
linked into ``build/include/botan``. Templates are processed to create the
|
||||
Makefile, ``build.h`` and other artifacts.
|
||||
|
||||
When Modifying ``configure.py``
|
||||
--------------------------------
|
||||
|
||||
Run ``./src/scripts/ci_build.py lint`` to run Pylint checks after any change.
|
||||
|
||||
Template Language
|
||||
--------------------
|
||||
|
||||
Various output files are generated by processing input files using a simple
|
||||
template language. All input files are stored in ``src/build-data`` and use the
|
||||
suffix ``.in``. Anything not recognized as a template command is passed through
|
||||
to the output unmodified. The template elements are:
|
||||
|
||||
* Variable substitution, ``%{variable_name}``. The configure script creates
|
||||
many variables for various purposes, this allows getting their value within
|
||||
the output. If a variable is not defined, an error occurs.
|
||||
|
||||
If a variable reference ends with ``|upper``, the value is uppercased before
|
||||
being inserted into the template output.
|
||||
|
||||
* Iteration, ``%{for variable} block %{endfor}``. This iterates over a list and
|
||||
repeats the block as many times as it is included. Variables within the block
|
||||
are expanded. The two template elements ``%{for ...}`` and ``%{endfor}`` must
|
||||
appear on lines with no text before or after.
|
||||
|
||||
* Conditional inclusion, ``%{if variable} block %{endif}``. If the variable
|
||||
named is defined and true (in the Python sense of the word; if the variable
|
||||
is empty or zero it is considered false), then the block will be included and
|
||||
any variables expanded. As with the for loop syntax, both the start and end
|
||||
of the conditional must be on their own lines with no additional text.
|
||||
|
||||
Build.h
|
||||
-------
|
||||
|
||||
The ``build.h`` header file is generated and overwritten each time the
|
||||
``configure.py`` script is executed. This header can be included in any header
|
||||
or source file and provides plenty of compile-time information in the form of
|
||||
preprocessor ``#define``\ s.
|
||||
|
||||
It is helpful to check which modules are included in the current build of the
|
||||
library via macro defines of the form "BOTAN_HAS" followed by the module name.
|
||||
Also, it contains :ref:`version information macros <versioning>` and compile-time
|
||||
library configurations.
|
||||
|
||||
Adding a new module
|
||||
--------------------
|
||||
|
||||
Create a directory in the appropriate place and create a ``info.txt`` file.
|
||||
|
||||
Syntax of ``info.txt``
|
||||
------------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
The syntax described here is documented to make it easier to use
|
||||
and understand, but it is not considered part of the public API
|
||||
contract. That is, the developers are allowed to change the syntax
|
||||
at any time on the assumption that all users are contained within
|
||||
the library itself. If that happens this document will be updated.
|
||||
|
||||
Modules and files describing information about the system use the same
|
||||
parser and have common syntactical elements.
|
||||
|
||||
Comments begin with '#' and continue to end of line.
|
||||
|
||||
There are three main types: maps, lists, and variables.
|
||||
|
||||
A map has a syntax like::
|
||||
|
||||
<MAP_NAME>
|
||||
NAME1 -> VALUE1
|
||||
NAME2 -> VALUE2
|
||||
...
|
||||
</MAP_NAME>
|
||||
|
||||
The interpretation of the names and values will depend on the map's name
|
||||
and what type of file is being parsed.
|
||||
|
||||
A list has similar syntax, it just doesn't have values::
|
||||
|
||||
<LIST_NAME>
|
||||
ELEM1
|
||||
ELEM2
|
||||
...
|
||||
</LIST_NAME>
|
||||
|
||||
Lastly there are single value variables like::
|
||||
|
||||
VAR1 SomeValue
|
||||
VAR2 "Quotes Can Be Used (And will be stripped out)"
|
||||
VAR3 42
|
||||
|
||||
Variables can have string, integer or boolean values. Boolean values
|
||||
are specified with 'yes' or 'no'.
|
||||
|
||||
Module Syntax
|
||||
---------------------
|
||||
|
||||
The ``info.txt`` files have the following elements. Not all are required; a minimal
|
||||
file for a module with no dependencies might just contain a macro define and module_info.
|
||||
|
||||
Lists:
|
||||
* ``comment`` and ``warning`` provides block-comments which
|
||||
are displayed to the user at build time.
|
||||
* ``requires`` is a list of module dependencies. An ``os_features`` can be
|
||||
specified as a condition for needing the dependency by writing it before
|
||||
the module name and separated by a ``?``, e.g. ``rtlgenrandom?dyn_load``.
|
||||
* ``header:internal`` is the list of headers (from the current module)
|
||||
which are internal-only.
|
||||
* ``header:public`` is a the list of headers (from the
|
||||
current module) which should be exported for public use. If neither
|
||||
``header:internal`` nor ``header:public`` are used then all headers
|
||||
in the current directory are assumed internal.
|
||||
|
||||
.. note:: If you omit a header from both internal and public lists, it will
|
||||
be ignored.
|
||||
|
||||
* ``header:external`` is used when naming headers which are included
|
||||
in the source tree but might be replaced by an external version. This is used
|
||||
for the PKCS11 headers.
|
||||
* ``arch`` is a list of architectures this module may be used on.
|
||||
* ``isa`` lists ISA features which must be enabled to use this module.
|
||||
Can be proceeded by an ``arch`` name followed by a ``:`` if it is only needed
|
||||
on a specific architecture, e.g. ``x86_64:ssse3``.
|
||||
* ``cc`` is a list of compilers which can be used with this module. If the
|
||||
compiler name is suffixed with a version (like "gcc:5.0") then only compilers
|
||||
with that minimum version can use the module. If you need to exclude just
|
||||
one specific compiler (for example because that compiler miscompiles the code
|
||||
in the module), you can prefix a compiler name with ``!`` - like ``!msvc``.
|
||||
* ``os_features`` is a list of OS features which are required in order to use this
|
||||
module. Each line can specify one or more features combined with ','. Alternatives
|
||||
can be specified on additional lines.
|
||||
|
||||
Maps:
|
||||
* ``defines`` is a map from macros to datestamps. These macros will be defined in
|
||||
the generated ``build.h``.
|
||||
* ``module_info`` contains documentation-friendly information about the module.
|
||||
Available mappings:
|
||||
|
||||
* ``name`` must contain a human-understandable name for the module
|
||||
* ``brief`` may provide a short description about the module's contents
|
||||
* ``type`` specifies the type of the module (defaults to ``Public``)
|
||||
|
||||
* ``Public`` Library users can directly interact with this module. E.g.
|
||||
they may enable or disable the module at will during build.
|
||||
* ``Internal`` Library users must not directly interact with this module.
|
||||
It is enabled and used as required by other modules.
|
||||
* ``Virtual`` This module does not contain any implementation but acts as
|
||||
a container for other sub-modules. It cannot be interacted with by the
|
||||
library user and cannot be depended upon directly.
|
||||
|
||||
* ``libs`` specifies additional libraries which should be linked if this module is
|
||||
included. It maps from the OS name to a list of libraries (comma seperated).
|
||||
* ``frameworks`` is a macOS/iOS specific feature which maps from an OS name to
|
||||
a framework.
|
||||
|
||||
Variables:
|
||||
* ``load_on`` Can take on values ``never``, ``always``, ``auto``, ``dep`` or ``vendor``.
|
||||
TODO describe the behavior of these
|
||||
* ``endian`` Required endian for the module (``any`` (default), ``little``, ``big``)
|
||||
|
||||
An example::
|
||||
|
||||
# Disable this by default
|
||||
load_on never
|
||||
|
||||
<isa>
|
||||
sse2
|
||||
</isa>
|
||||
|
||||
<defines>
|
||||
DEFINE1 -> 20180104
|
||||
DEFINE2 -> 20190301
|
||||
</defines>
|
||||
|
||||
<module_info>
|
||||
name -> "This Is Just To Say"
|
||||
brief -> "Contains a poem by William Carlos Williams"
|
||||
</module_info>
|
||||
|
||||
<comment>
|
||||
I have eaten
|
||||
the plums
|
||||
that were in
|
||||
the icebox
|
||||
</comment>
|
||||
|
||||
<warning>
|
||||
There are no more plums
|
||||
</warning>
|
||||
|
||||
<header:public>
|
||||
header1.h
|
||||
</header:public>
|
||||
|
||||
<header:internal>
|
||||
header_helper.h
|
||||
whatever.h
|
||||
</header:internal>
|
||||
|
||||
<arch>
|
||||
x86_64
|
||||
</arch>
|
||||
|
||||
<cc>
|
||||
gcc:4.9 # gcc 4.8 doesn't work for <reasons>
|
||||
clang
|
||||
</cc>
|
||||
|
||||
# Can work with POSIX+getentropy or Win32
|
||||
<os_features>
|
||||
posix1,getentropy
|
||||
win32
|
||||
</os_features>
|
||||
|
||||
<frameworks>
|
||||
macos -> FramyMcFramerson
|
||||
</frameworks>
|
||||
|
||||
<libs>
|
||||
qnx -> foo,bar,baz
|
||||
solaris -> socket
|
||||
</libs>
|
||||
|
||||
Supporting a new CPU type
|
||||
---------------------------
|
||||
|
||||
CPU information is stored in ``src/build-data/arch``.
|
||||
|
||||
There is also a file ``src/build-data/detect_arch.cpp`` which is used
|
||||
for build-time architecture detection using the compiler preprocessor.
|
||||
Supporting this is optional but recommended.
|
||||
|
||||
Lists:
|
||||
* ``aliases`` is a list of alternative names for the CPU architecture.
|
||||
* ``isa_extensions`` is a list of possible ISA extensions that can be used on
|
||||
this architecture. For example x86-64 has extensions "sse2", "ssse3",
|
||||
"avx2", "aesni", ...
|
||||
|
||||
Variables:
|
||||
* ``endian`` if defined should be "little" or "big". This can also be
|
||||
controlled or overridden at build time.
|
||||
* ``family`` can specify a family group for several related architecture.
|
||||
For example both x86_32 and x86_64 use ``family`` of "x86".
|
||||
* ``wordsize`` is the default wordsize, which controls the size of limbs
|
||||
in the multi precision integers. If not set, defaults to 32.
|
||||
|
||||
Supporting a new compiler
|
||||
---------------------------
|
||||
|
||||
Compiler information is stored in ``src/build-data/cc``. Looking over
|
||||
those files will probably help understanding, especially the ones for
|
||||
GCC and Clang which are most complete.
|
||||
|
||||
In addition to the info file, for compilers there is a file
|
||||
``src/build-data/detect_version.cpp``. The ``configure.py`` script runs the
|
||||
preprocessor over this file to attempt to detect the compiler
|
||||
version. Supporting this is not strictly necessary.
|
||||
|
||||
Maps:
|
||||
* ``binary_link_commands`` gives the command to use to run the linker,
|
||||
it maps from operating system name to the command to use. It uses
|
||||
the entry "default" for any OS not otherwise listed.
|
||||
* ``cpu_flags_no_debug`` unused, will be removed
|
||||
* ``cpu_flags`` used to emit CPU specific flags, for example LLVM
|
||||
bitcode target uses ``-emit-llvm`` flag. Rarely needed.
|
||||
* ``isa_flags`` maps from CPU extensions (like NEON or AES-NI) to
|
||||
compiler flags which enable that extension. These have the same name
|
||||
as the ISA flags listed in the architecture files.
|
||||
* ``lib_flags`` has a single possible entry "debug" which if set maps
|
||||
to additional flags to pass when building a debug library.
|
||||
Rarely needed.
|
||||
* ``mach_abi_linking`` specifies flags to enable when building and
|
||||
linking on a particular CPU. This is usually flags that modify
|
||||
ABI. There is a special syntax supported here
|
||||
"all!os1,arch1,os2,arch2" which allows setting ABI flags which are
|
||||
used for all but the named operating systems and/or architectures.
|
||||
* ``sanitizers`` is a map of sanitizers the compiler supports. It must
|
||||
include "default" which is a list of sanitizers to include by default
|
||||
when sanitizers are requested. The other keys should map to compiler
|
||||
flags.
|
||||
* ``so_link_commands`` maps from operating system to the command to
|
||||
use to build a shared object.
|
||||
|
||||
Variables:
|
||||
* ``binary_name`` the default name of the compiler binary.
|
||||
* ``linker_name`` the name of the linker to use with this compiler.
|
||||
* ``macro_name`` a macro of the for ``BOTAN_BUILD_COMPILER_IS_XXX``
|
||||
will be defined.
|
||||
* ``output_to_object`` (default "-o") gives the compiler option used to
|
||||
name the output object.
|
||||
* ``output_to_exe`` (default "-o") gives the compiler option used to
|
||||
name the output object.
|
||||
* ``add_include_dir_option`` (default "-I") gives the compiler option used
|
||||
to specify an additional include dir.
|
||||
* ``add_lib_dir_option`` (default "-L") gives the compiler option used
|
||||
to specify an additional library dir.
|
||||
* ``add_sysroot_option`` gives the compiler option used to specify the sysroot.
|
||||
* ``add_lib_option`` (default "-l%s") gives the compiler option to
|
||||
link in a library. ``%s`` will be replaced with the library name.
|
||||
* ``add_framework_option`` (default "-framework") gives the compiler option
|
||||
to add a macOS framework.
|
||||
* ``preproc_flags`` (default "-E") gives the compiler option used to run
|
||||
the preprocessor.
|
||||
* ``compile_flags`` (default "-c") gives the compiler option used to compile a file.
|
||||
* ``debug_info_flags`` (default "-g") gives the compiler option used to enable debug info.
|
||||
* ``optimization_flags`` gives the compiler optimization flags to use.
|
||||
* ``size_optimization_flags`` gives compiler optimization flags to use when
|
||||
compiling for size. If not set then ``--optimize-for-size`` will use
|
||||
the default optimization flags.
|
||||
* ``sanitizer_optimization_flags`` gives compiler optimization flags to use
|
||||
when building with sanitizers.
|
||||
* ``coverage_flags`` gives the compiler flags to use when generating coverage
|
||||
information.
|
||||
* ``stack_protector_flags`` gives compiler flags to enable stack overflow checking.
|
||||
* ``shared_flags`` gives compiler flags to use when generation shared libraries.
|
||||
* ``lang_flags`` gives compiler flags used to enable the required version of C++.
|
||||
* ``lang_binary_linker_flags`` gives flags to be passed to the linker when creating a binary
|
||||
* ``warning_flags`` gives warning flags to enable.
|
||||
* ``maintainer_warning_flags`` gives extra warning flags to enable during maintainer
|
||||
mode builds.
|
||||
* ``visibility_build_flags`` gives compiler flags to control symbol visibility
|
||||
when generation shared libraries.
|
||||
* ``visibility_attribute`` gives the attribute to use in the ``BOTAN_DLL`` macro
|
||||
to specify visibility when generation shared libraries.
|
||||
* ``ar_command`` gives the command to build static libraries
|
||||
* ``ar_options`` gives the options to pass to ``ar_command``, if not set here
|
||||
takes this from the OS specific information.
|
||||
* ``ar_output_to`` gives the flag to pass to ``ar_command`` to specify where to
|
||||
output the static library.
|
||||
* ``werror_flags`` gives the complier flags to treat warnings as errors.
|
||||
|
||||
Supporting a new OS
|
||||
---------------------------
|
||||
|
||||
Operating system information is stored in ``src/build-data/os``.
|
||||
|
||||
Lists:
|
||||
* ``aliases`` is a list of alternative names which will be accepted
|
||||
* ``target_features`` is a list of target specific OS features. Some of these
|
||||
are supported by many OSes (for example "posix1") others are specific to
|
||||
just one or two OSes (such as "getauxval"). Adding a value here causes a new
|
||||
macro ``BOTAN_TARGET_OS_HAS_XXX`` to be defined at build time. Use
|
||||
``configure.py --list-os-features`` to list the currently defined OS
|
||||
features.
|
||||
* ``feature_macros`` is a list of macros to define.
|
||||
|
||||
Variables:
|
||||
* ``ar_command`` gives the command to build static libraries
|
||||
* ``ar_options`` gives the options to pass to ``ar_command``
|
||||
* ``ar_output_to`` gives the flag to pass to ``ar_command`` to specify where to
|
||||
output the static library.
|
||||
* ``bin_dir`` (default "bin") specifies where binaries should be installed,
|
||||
relative to install_root.
|
||||
* ``cli_exe_name`` (default "botan") specifies the name of the command line utility.
|
||||
* ``default_compiler`` specifies the default compiler to use for this OS.
|
||||
* ``doc_dir`` (default "doc") specifies where documentation should be installed,
|
||||
relative to install_root
|
||||
* ``header_dir`` (default "include") specifies where include files
|
||||
should be installed, relative to install_root
|
||||
* ``install_root`` (default "/usr/local") specifies where to install
|
||||
by default.
|
||||
* ``lib_dir`` (default "lib") specifies where library should be installed,
|
||||
relative to install_root.
|
||||
* ``lib_prefix`` (default "lib") prefix to add to the library name
|
||||
* ``library_name``
|
||||
* ``man_dir`` specifies where man files should be installed, relative to install_root
|
||||
* ``obj_suffix`` (default "o") specifies the suffix used for object files
|
||||
* ``program_suffix`` (default "") specifies the suffix used for executables
|
||||
* ``shared_lib_symlinks`` (default "yes) specifies if symbolic names should be
|
||||
created from the base and patch soname to the library name.
|
||||
* ``soname_pattern_abi``
|
||||
* ``soname_pattern_base``
|
||||
* ``soname_pattern_patch``
|
||||
* ``soname_suffix`` file extension to use for shared library if ``soname_pattern_base``
|
||||
is not specified.
|
||||
* ``static_suffix`` (default "a") file extension to use for static library.
|
||||
* ``use_stack_protector`` (default "true") specify if by default stack smashing
|
||||
protections should be enabled.
|
||||
* ``uses_pkg_config`` (default "yes") specify if by default a pkg-config file
|
||||
should be created.
|
@ -1,20 +0,0 @@
|
||||
Developer Reference
|
||||
=====================
|
||||
|
||||
This section contains information useful to people making
|
||||
contributions to the library
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
contributing
|
||||
configure
|
||||
test_framework
|
||||
continuous_integration
|
||||
fuzzing
|
||||
release_process
|
||||
todo
|
||||
os
|
||||
oids
|
||||
reading_list
|
||||
mistakes
|
@ -1,52 +0,0 @@
|
||||
Continuous Integration and Automated Testing
|
||||
===============================================
|
||||
|
||||
CI Build Script
|
||||
----------------
|
||||
|
||||
The Github Actions builds are orchestrated using a script
|
||||
``src/scripts/ci_build.py``. This allows one to easily reproduce the CI process
|
||||
on a local machine.
|
||||
|
||||
Github Actions
|
||||
---------------
|
||||
|
||||
https://github.com/randombit/botan/actions/workflows/ci.yml
|
||||
|
||||
Github Actions is the primary CI, and tests the Linux, Windows, macOS, and iOS
|
||||
builds. Among other things it runs tests using valgrind, cross-compilation
|
||||
for various architectures (currently including ARM and PPC64), MinGW build,
|
||||
and a build that produces the coverage report.
|
||||
|
||||
The Github Actions configuration is in ``.github/workflows/ci.yml`` which
|
||||
executes platform dependent setup scripts ``src/scripts/ci/setup_gh_actions.sh``
|
||||
or ``src/scripts/ci/setup_gh_actions.ps1`` and ``.../setup_gh_actions_after_vcvars.ps1``
|
||||
to install needed packages and detect certain platform specifics like compiler
|
||||
cache locations.
|
||||
|
||||
Then ``src/scripts/ci_build.py`` is invoked to steer the actual build and test
|
||||
runs.
|
||||
|
||||
Github Actions (nightly)
|
||||
-------------------------
|
||||
|
||||
https://github.com/randombit/botan/actions/workflows/nightly.yml
|
||||
|
||||
Some checks are just too slow to include in the main CI builds. These
|
||||
are instead delegated to a scheduled job that runs every night against
|
||||
master.
|
||||
|
||||
Currently these checks include a full run of ``valgrind`` (the valgrind build in
|
||||
CI only runs a subset of the tests), and a run of ``clang-tidy`` with all
|
||||
warnings (that we are currently clean for) enabled. Each of these jobs takes
|
||||
about an hour to run. In the main CI, we aim to have no job take more than
|
||||
half an hour.
|
||||
|
||||
OSS-Fuzz
|
||||
----------
|
||||
|
||||
https://github.com/google/oss-fuzz/
|
||||
|
||||
OSS-Fuzz is a distributed fuzzer run by Google. Every night, the fuzzer harnesses
|
||||
in ``src/fuzzer`` are built and run on many machines, with any findings reported
|
||||
to the developers via email.
|
@ -1,299 +0,0 @@
|
||||
|
||||
Notes for New Contributors
|
||||
===================================
|
||||
|
||||
Source Code Layout
|
||||
-------------------------------------------------
|
||||
|
||||
Under ``src`` there are directories
|
||||
|
||||
* ``lib`` is the library itself, more on that below
|
||||
* ``cli`` is the command line application ``botan``
|
||||
* ``tests`` contain what you would expect. Input files go under ``tests/data``.
|
||||
* ``python/botan3.py`` is the Python ctypes wrapper
|
||||
* ``bogo_shim`` contains the shim binary and configuration for
|
||||
`BoringSSL's TLS test suite <https://github.com/google/boringssl/tree/master/ssl/test>`_
|
||||
* ``fuzzer`` contains fuzz targets for various modules of the library
|
||||
* ``build-data`` contains files read by the configure script. For
|
||||
example ``build-data/cc/gcc.txt`` describes various gcc options.
|
||||
* ``examples`` contains usage examples used in the documentation.
|
||||
* ``scripts`` contains misc scripts: install, distribution, various
|
||||
codegen things. Scripts controlling CI go under ``scripts/ci``.
|
||||
* ``configs`` contains configuration files tools like pylint
|
||||
* ``editors`` contains configuration files for editors like vscode and emacs
|
||||
|
||||
Under ``doc`` one finds the sources of this documentation
|
||||
|
||||
Library Layout
|
||||
----------------------------------------
|
||||
|
||||
Under ``src/lib`` are several directories
|
||||
|
||||
* ``asn1`` is the DER encoder/decoder
|
||||
* ``base`` defines some high level types
|
||||
* ``block`` contains the block cipher implementations
|
||||
* ``codec`` has hex, base64, base32, base58
|
||||
* ``compat`` a (partial) compatibility layer for the libsodium API
|
||||
* ``compression`` has the compression wrappers (zlib, bzip2, lzma)
|
||||
* ``entropy`` has various entropy sources used by some of the RNGs
|
||||
* ``ffi`` is the C99 API
|
||||
* ``filters`` is a filter/pipe API for data transforms
|
||||
* ``hash`` contains the hash function implementations
|
||||
* ``kdf`` contains the key derivation functions
|
||||
* ``mac`` contains the message authentication codes
|
||||
* ``math`` is the big integer math library. It is divided into three parts:
|
||||
``mp`` which are the low level algorithms; ``bigint`` which is a C++ wrapper
|
||||
around ``mp``, and ``numbertheory`` which contains higher level algorithms like
|
||||
primality testing and exponentiation
|
||||
* ``misc`` contains odds and ends: format preserving encryption, SRP, threshold
|
||||
secret sharing, all or nothing transform, and others
|
||||
* ``modes`` contains block cipher modes (CBC, GCM, etc)
|
||||
* ``passhash`` contains password hashing algorithms for authentication
|
||||
* ``pbkdf`` contains password hashing algorithms for key derivation
|
||||
* ``pk_pad`` contains padding schemes for public key algorithms
|
||||
* ``prov`` contains bindings to external libraries such as PKCS #11
|
||||
* ``psk_db`` contains a generic interface for a Pre-Shared-Key database
|
||||
* ``pubkey`` contains the public key algorithms
|
||||
* ``rng`` contains the random number generators
|
||||
* ``stream`` contains the stream ciphers
|
||||
* ``tls`` contains the TLS implementation
|
||||
* ``utils`` contains various utility functions and types
|
||||
* ``x509`` is X.509 certificates, PKCS #10 requests, OCSP
|
||||
|
||||
Each of these folders can contain subfolders which are treated as modules if they
|
||||
contain an ``info.txt`` file. These submodules have an implicit dependency on their
|
||||
parent module. The chapter :ref:`configure_script` contains more information on
|
||||
Botan's module architecture.
|
||||
|
||||
Sending patches
|
||||
----------------------------------------
|
||||
|
||||
All contributions should be submitted as pull requests via GitHub
|
||||
(https://github.com/randombit/botan). If you are planning a large
|
||||
change, open a discussion ticket on github before starting out to make
|
||||
sure you are on the right path. And once you have something written,
|
||||
even if it is not complete/ready to go, feel free to open a draft PR
|
||||
for early review and comment.
|
||||
|
||||
If possible please sign your git commits using a PGP key.
|
||||
See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for
|
||||
instructions on how to set this up.
|
||||
|
||||
Depending on what your change is, your PR should probably also include an update
|
||||
to ``news.rst`` with a note explaining the change. If your change is a
|
||||
simple bug fix, a one sentence description is perhaps sufficient. If there is an
|
||||
existing ticket on GitHub with discussion or other information, reference it in
|
||||
your change note as 'GH #000'.
|
||||
|
||||
Update ``doc/credits.txt`` with your information so people know what you did!
|
||||
|
||||
If you are interested in contributing but don't know where to start check out
|
||||
``doc/dev_ref/todo.rst`` for some ideas - these are changes we would almost
|
||||
certainly accept once they've passed code review.
|
||||
|
||||
Also, try building and testing it on whatever hardware you have handy,
|
||||
especially unusual platforms, or using C++ compilers other than the regularly
|
||||
tested GCC, Clang, and Visual Studio.
|
||||
|
||||
FFI Additions
|
||||
----------------
|
||||
|
||||
If adding a new function declaration to ``ffi.h``, the same PR must also add the
|
||||
same declaration in the Python binding ``botan3.py``, in addition the new API
|
||||
functionality must be exposed to Python and a test written in Python.
|
||||
|
||||
Git Usage
|
||||
----------------------------------------
|
||||
|
||||
Do *NOT* merge ``master`` into your topic branch, this creates needless commits
|
||||
and noise in history. Instead, as needed, rebase your branch against master
|
||||
(``git rebase -i master``) and force push the branch to update the PR. If the
|
||||
GitHub PR page does not report any merge conflicts and nobody asks you to
|
||||
rebase, you don't need to rebase.
|
||||
|
||||
Try to keep your history clean and use rebase to squash your commits as
|
||||
needed. If your diff is less than roughly 100 lines, it should probably be a
|
||||
single commit. Only split commits as needed to help with review/understanding of
|
||||
the change.
|
||||
|
||||
Python
|
||||
----------------------------------------
|
||||
|
||||
Scripts should be in Python 3 whenever possible.
|
||||
|
||||
For configure.py (and helper scripts install.py, cleanup.py and build_docs.py)
|
||||
the target is stock (no modules outside the standard library) CPython 3.x.
|
||||
Support for PyPy, etc is great when viable (in the sense of not causing problems
|
||||
for 3.x, and not requiring huge blocks of version dependent code). As running
|
||||
this program successfully is required for a working build, making it as portable
|
||||
as possible is considered key.
|
||||
|
||||
The python wrapper botan3.py targets CPython 3.x, and latest PyPy. Note that
|
||||
a single file is used to avoid dealing with any of Python's various crazy module
|
||||
distribution issues.
|
||||
|
||||
For random scripts not typically run by an end-user (codegen, visualization, and
|
||||
so on) there isn't any need to worry about platform independence. Here it's fine
|
||||
to depend on any useful modules such as graphviz or matplotlib, regardless if it
|
||||
is available from a stock CPython install.
|
||||
|
||||
Build Tools and Hints
|
||||
----------------------------------------
|
||||
|
||||
If you don't already use it for all your C/C++ development, install ``ccache``
|
||||
(or on Windows, ``sccache``) right now, and configure a large cache on a fast
|
||||
disk. It allows for very quick rebuilds by caching the compiler output.
|
||||
|
||||
Use ``--enable-sanitizers=`` flag to enable various sanitizer checks. Supported
|
||||
values including "address" and "undefined" for GCC and Clang. GCC also supports
|
||||
"iterator" (checked iterators), and Clang supports "memory" (MSan) and
|
||||
"coverage" (for fuzzing).
|
||||
|
||||
On Linux if you have the ``lcov`` and ``gcov`` tools installed, then running
|
||||
``./src/scripts/ci_build.py coverage`` will produce a coverage enabled build,
|
||||
run the tests, test the fuzzers against a corpus, and produce an HTML report
|
||||
of total coverage. This coverage build requires the development headers for
|
||||
zlib, bzip2, liblzma, TrouSerS (libtspi), and Sqlite3.
|
||||
|
||||
Copyright Notice
|
||||
----------------------------------------
|
||||
|
||||
At the top of any new file add a comment with a copyright and a reference to the
|
||||
license, for example::
|
||||
|
||||
/*
|
||||
* (C) 202x <You>
|
||||
*
|
||||
* Botan is released under the Simplified BSD License (see license.txt)
|
||||
*/
|
||||
|
||||
If you are making a substantial or non-trivial change to an existing file, add
|
||||
or update your own copyright statement at the top of each file.
|
||||
|
||||
Style Conventions
|
||||
----------------------------------------
|
||||
|
||||
When writing your code remember the need for it to be easily understood by
|
||||
reviewers and auditors, both at the time of the patch submission and in the
|
||||
future.
|
||||
|
||||
Avoid complicated template metaprogramming where possible. It has its places but
|
||||
should be used judiciously.
|
||||
|
||||
When designing a new API (for use either by library users or just internally)
|
||||
try writing out the calling code first. That is, write out some code calling
|
||||
your idealized API, then just implement that API. This can often help avoid
|
||||
cut-and-paste by creating the correct abstractions needed to solve the problem
|
||||
at hand.
|
||||
|
||||
The C++11 ``auto`` keyword is very convenient but only use it when the type
|
||||
truly is obvious (considering also the potential for unexpected integer
|
||||
conversions and the like, such as an apparent uint8_t being promoted to an int).
|
||||
|
||||
Unless there is a specific reason otherwise (eg due to calling some C API which
|
||||
requires exactly a ``long*`` be provided) integer types should be either
|
||||
``(u)intXX_t`` or ``size_t``. If the variable is used for integer values of "no
|
||||
particular size", as in the loop ``for(some_type i = 0; i != 100; ++i)`` then
|
||||
the type should be ``size_t``. Use one of the specific size integer types only
|
||||
when there is a algorithmic/protocol reason to use an integer of that size. For
|
||||
example if a parsing a protocol that uses 16-bit integer fields to encode a
|
||||
length, naturally one would use ``uint16_t`` there.
|
||||
|
||||
If a variable is defined and not modified, declare it ``const``. Some exception
|
||||
for very short-lived variables, but generally speaking being able to read the
|
||||
declaration and know it will not be modified is useful.
|
||||
|
||||
Use ``override`` annotations whenever overriding a virtual function. If
|
||||
introducing a new type that is not intended for further derivation, mark it ``final``.
|
||||
|
||||
Avoid explicit ``new`` or (especially) explicit ``delete``: use RAII,
|
||||
``make_unique``, etc.
|
||||
|
||||
Use ``m_`` prefix on all member variables.
|
||||
|
||||
``clang-format`` is used for all C++ formatting. The configuration is
|
||||
in ``.clang-format`` in the root directory. You can rerun the
|
||||
formatter using ``make fmt`` or by invoking the script
|
||||
``src/scripts/dev_tools/run_clang_format.py``. If the output would be
|
||||
truly horrible, it is allowed to disable formatting for a specific
|
||||
area using ``// clang-format off`` annotations.
|
||||
|
||||
.. note::
|
||||
|
||||
Since the output of clang-format varies from version to version, we
|
||||
currently require using exactly ``clang-format 15``.
|
||||
|
||||
Use braces on both sides of if/else blocks, even if only using a single
|
||||
statement.
|
||||
|
||||
Avoid ``using namespace`` declarations, even inside of single functions. One
|
||||
allowed exception is ``using namespace std::placeholders`` in functions which
|
||||
use ``std::bind``. (But, don't use ``std::bind`` - use a lambda instead).
|
||||
|
||||
Use ``::`` to explicitly refer to the global namespace (eg, when calling an OS
|
||||
or external library function like ``::select`` or ``::sqlite3_open``).
|
||||
|
||||
Use of External Dependencies
|
||||
----------------------------------------
|
||||
|
||||
Compiler Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The library should always be as functional as possible when compiled with just
|
||||
Standard C++20. However, feel free to use the full language.
|
||||
|
||||
Use of compiler extensions is fine whenever appropriate; this is typically
|
||||
restricted to a single file or an internal header. Compiler extensions used
|
||||
currently include native uint128_t, SIMD intrinsics, inline asm syntax and so
|
||||
on, so there are some existing examples of appropriate use.
|
||||
|
||||
Generally intrinsics or inline asm is preferred over bare assembly to avoid
|
||||
calling convention issues among different platforms; the improvement in
|
||||
maintainability is seen as worth any potential performance tradeoff. One risk
|
||||
with intrinsics is that the compiler might rewrite your clever const-time SIMD
|
||||
into something with a conditional jump, but code intended to be const-time
|
||||
should in any case be annotated (using ``CT::poison``) so it can be checked at
|
||||
runtime with tools.
|
||||
|
||||
Operating System Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you're adding a small OS dependency in some larger piece of code, try to
|
||||
contain the actual non-portable operations to utils/os_utils.* and then call
|
||||
them from there.
|
||||
|
||||
As a policy, operating systems which are not supported by their original vendor
|
||||
are not supported by Botan either. Patches that complicate the code in order to
|
||||
support obsolete operating systems will likely be rejected. In writing OS
|
||||
specific code, feel free to assume roughly POSIX 2008, or for Windows, Windows 8
|
||||
/Server 2012 (which are as of this writing the oldest versions still supported
|
||||
by Microsoft).
|
||||
|
||||
Some operating systems, such as OpenBSD, only support the latest release. For
|
||||
such cases, it's acceptable to add code that requires APIs added in the most
|
||||
recent release of that OS as soon as the release is available.
|
||||
|
||||
Library Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Any external library dependency - even optional ones - is met with as one PR
|
||||
submitter put it "great skepticism".
|
||||
|
||||
At every API boundary there is potential for confusion that does not exist when
|
||||
the call stack is all contained within the boundary. So the additional API
|
||||
really needs to pull its weight. For example a simple text parser or such which
|
||||
can be trivially implemented is not really for consideration. As a rough idea of
|
||||
the bar, equate the viewed cost of an external dependency as at least 1000
|
||||
additional lines of code in the library. That is, if the library really does
|
||||
need this functionality, and it can be done in the library for less than that,
|
||||
then it makes sense to just write the code. Yup.
|
||||
|
||||
Currently the (optional) external dependencies of the library are several
|
||||
compression libraries (zlib, bzip2, lzma), sqlite3 database, Trousers (TPM
|
||||
integration), plus various operating system utilities like basic filesystem
|
||||
operations. These provide major pieces of functionality which seem worth the
|
||||
trouble of maintaining an integration with.
|
||||
|
||||
At this point the most plausible examples of an appropriate new external
|
||||
dependency are all deeper integrations with system level cryptographic
|
||||
interfaces (CommonCrypto, CryptoAPI, /dev/crypto, iOS keychain, TPM 2.0, etc)
|
@ -1,91 +0,0 @@
|
||||
Fuzzing The Library
|
||||
============================
|
||||
|
||||
Botan comes with a set of fuzzing endpoints which can be used to test
|
||||
the library.
|
||||
|
||||
.. highlight:: shell
|
||||
|
||||
Fuzzing with libFuzzer
|
||||
------------------------
|
||||
|
||||
To fuzz with libFuzzer (https://llvm.org/docs/LibFuzzer.html), you'll first
|
||||
need to compile libFuzzer::
|
||||
|
||||
$ svn co https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer
|
||||
$ cd libFuzzer && clang -c -g -O2 -std=c++11 *.cpp
|
||||
$ ar cr libFuzzer.a libFuzzer/*.o
|
||||
|
||||
Then build the fuzzers::
|
||||
|
||||
$ ./configure.py --cc=clang --build-fuzzer=libfuzzer --unsafe-fuzzer-mode \
|
||||
--with-debug-info --enable-sanitizers=coverage,address,undefined
|
||||
$ make fuzzers
|
||||
|
||||
Enabling 'coverage' sanitizer flags is required for libFuzzer to work.
|
||||
Address sanitizer and undefined sanitizer are optional.
|
||||
|
||||
The fuzzer binaries will be in `build/fuzzer`. Simply pick one and run it, optionally
|
||||
also passing a directory containing corpus inputs.
|
||||
|
||||
Using `libfuzzer` build mode implicitly assumes the fuzzers need to
|
||||
link with `libFuzzer`; if another library is needed (for example in
|
||||
OSS-Fuzz, which uses `libFuzzingEngine`), use the flag
|
||||
`--with-fuzzer-lib` to specify the desired name.
|
||||
|
||||
Fuzzing with AFL
|
||||
--------------------
|
||||
|
||||
To fuzz with AFL (http://lcamtuf.coredump.cx/afl/)::
|
||||
|
||||
$ ./configure.py --with-sanitizers --build-fuzzer=afl --unsafe-fuzzer-mode --cc-bin=afl-g++
|
||||
$ make fuzzers
|
||||
|
||||
For AFL sanitizers are optional. You can also use `afl-clang-fast++`
|
||||
or `afl-clang++`, be sure to set `--cc=clang` also.
|
||||
|
||||
The fuzzer binaries will be in `build/fuzzer`. To run them you need to
|
||||
run under `afl-fuzz`::
|
||||
|
||||
$ afl-fuzz -i corpus_path -o output_path ./build/fuzzer/binary
|
||||
|
||||
Fuzzing with TLS-Attacker
|
||||
--------------------------
|
||||
|
||||
TLS-Attacker (https://github.com/RUB-NDS/TLS-Attacker) includes a mode for fuzzing
|
||||
TLS servers. A prebuilt copy of TLS-Attacker is available in a git repository::
|
||||
|
||||
$ git clone --depth 1 https://github.com/randombit/botan-ci-tools.git
|
||||
|
||||
To run it against Botan's server::
|
||||
|
||||
$ ./configure.py --with-sanitizers
|
||||
$ make botan
|
||||
$ ./src/scripts/run_tls_attacker.py ./botan ./botan-ci-tools
|
||||
|
||||
Output and logs from the fuzzer are placed into `/tmp`. See the
|
||||
TLS-Attacker documentation for more information about how to use this
|
||||
tool.
|
||||
|
||||
Input Corpus
|
||||
-----------------------
|
||||
|
||||
AFL requires an input corpus, and libFuzzer can certainly make good
|
||||
use of it.
|
||||
|
||||
Some crypto corpus repositories include
|
||||
|
||||
* https://github.com/randombit/crypto-corpus
|
||||
* https://github.com/mozilla/nss-fuzzing-corpus
|
||||
* https://github.com/google/boringssl/tree/master/fuzz
|
||||
* https://github.com/openssl/openssl/tree/master/fuzz/corpora
|
||||
|
||||
Adding new fuzzers
|
||||
---------------------
|
||||
|
||||
New fuzzers are created by adding a source file to `src/fuzzers` which
|
||||
have the signature:
|
||||
|
||||
``void fuzz(const uint8_t in[], size_t len)``
|
||||
|
||||
After adding your fuzzer, rerun ``./configure.py`` and build.
|
@ -1,79 +0,0 @@
|
||||
Mistakes Were Made
|
||||
===================
|
||||
|
||||
These are mistakes made early on in the project's history which are difficult to
|
||||
fix now, but mentioned in the hope they may serve as an example for others.
|
||||
|
||||
C++ API
|
||||
---------
|
||||
|
||||
As an implementation language, I still think C++ is the best choice (or at least
|
||||
the best choice available in early '00s) at offering good performance,
|
||||
reasonable abstractions, and low overhead. But the user API should have been
|
||||
pure C with opaque structs (rather like the FFI layer, which was added much
|
||||
later). Then an expressive C++ API could be built on top of the C API. This
|
||||
would have given us a stable ABI, allowed C applications to use the library, and
|
||||
(these days) make it easier to progressively rewrite the library in Rust.
|
||||
|
||||
Public Algorithm Specific Classes
|
||||
------------------------------------
|
||||
|
||||
Classes like AES_128 and SHA_256 should never have been exposed to applications.
|
||||
Intead such operations should have been accessible only via the higher level
|
||||
interfaces (here BlockCipher and HashFunction). This would substantially reduce
|
||||
the overall API and ABI surface.
|
||||
|
||||
[These interfaces were made internal in 3.0]
|
||||
|
||||
Header Directories
|
||||
-------------------
|
||||
|
||||
It would have been better to install all headers as ``X/header.h``
|
||||
where ``X`` is the base dir in the source, eg ``block/aes128.h``,
|
||||
``hash/md5.h``, ...
|
||||
|
||||
Exceptions
|
||||
-----------
|
||||
|
||||
Constant ABI headaches from this, and it impacts performance and makes APIs
|
||||
harder to understand. Should have been handled with a result<> type instead.
|
||||
|
||||
Alternatively, and possibly more practically, there should have not been any
|
||||
exception hierarchy (or at least not one visible to users) - instead only the
|
||||
high level Exception type with contains an error type enum.
|
||||
|
||||
Virtual inheritance
|
||||
---------------------
|
||||
|
||||
This was used in the public key interfaces and the hierarchy is a tangle.
|
||||
Public and private keys should be distinct classes, with a function on private
|
||||
keys that creates a new object corresponding to the public key.
|
||||
|
||||
Cipher Interface
|
||||
------------------
|
||||
|
||||
The cipher interface taking a secure_vector that it reads from and writes to was
|
||||
an artifact of an earlier design which supported both compression and encryption
|
||||
in a single API. But it leads to inefficient copies.
|
||||
|
||||
(I am hoping this issue can be somewhat fixed by introducing a new cipher API
|
||||
and implementing the old API in terms of the new one.)
|
||||
|
||||
Pipe Interface
|
||||
----------------
|
||||
|
||||
On the surface this API seems very convenient and easy to use. And it is. But
|
||||
the downside is it makes the application code totally opaque; some bytes go into
|
||||
a Pipe object and then come out the end transformed in some way. What happens in
|
||||
between? Unless the Pipe was built in the same function and you can see the
|
||||
parameters to the constructor, there is no way to find out.
|
||||
|
||||
The problems with the Pipe API are documented, and it is no longer used within
|
||||
the library itself. But since many people seem to like it and many applications
|
||||
use it, we are stuck at least with maintaining it as it currently exists.
|
||||
|
||||
License
|
||||
---------
|
||||
|
||||
MIT is more widely used and doesn't have the ambiguity surrounding the
|
||||
various flavors of BSD.
|
@ -1,92 +0,0 @@
|
||||
Private OID Assignments
|
||||
==========================
|
||||
|
||||
The library uses some OIDs under a private arc assigned by IANA,
|
||||
1.3.6.1.4.1.25258
|
||||
|
||||
Values currently assigned are::
|
||||
|
||||
randombit OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 25258 }
|
||||
|
||||
publicKey OBJECT IDENTIFIER ::= { randombit 1 }
|
||||
|
||||
mceliece OBJECT IDENTIFIER ::= { publicKey 3 }
|
||||
-- { publicKey 4 } previously used as private X25519
|
||||
-- { publicKey 5 } previously used for XMSS draft 6
|
||||
gost-3410-with-sha256 OBJECT IDENTIFIER ::= { publicKey 6 1 }
|
||||
|
||||
kyber OBJECT IDENTIFIER ::= { publicKey 7 }
|
||||
kyber-90s OBJECT IDENTIFIER ::= { publicKey 11 }
|
||||
|
||||
kyber-512 OBJECT IDENTIFIER ::= { kyber 1 }
|
||||
kyber-768 OBJECT IDENTIFIER ::= { kyber 2 }
|
||||
kyber-1024 OBJECT IDENTIFIER ::= { kyber 3 }
|
||||
kyber-512-90s OBJECT IDENTIFIER ::= { kyber-90s 1 }
|
||||
kyber-768-90s OBJECT IDENTIFIER ::= { kyber-90s 2 }
|
||||
kyber-1024-90s OBJECT IDENTIFIER ::= { kyber-90s 3 }
|
||||
|
||||
xmss OBJECT IDENTIFIER ::= { publicKey 8 }
|
||||
|
||||
-- The current dilithium implementation is compatible with the reference
|
||||
-- implementation commit 3e9b9f1412f6c7435dbeb4e10692ea58f181ee51
|
||||
dilithium OBJECT IDENTIFIER ::= { publicKey 9 }
|
||||
dilithium-aes OBJECT IDENTIFIER ::= { publicKey 10 }
|
||||
|
||||
dilithium-4x4 OBJECT IDENTIFIER ::= { dilithium 1 }
|
||||
dilithium-6x5 OBJECT IDENTIFIER ::= { dilithium 2 }
|
||||
dilithium-8x7 OBJECT IDENTIFIER ::= { dilithium 3 }
|
||||
dilithium-aes-4x4 OBJECT IDENTIFIER ::= { dilithium-aes 1 }
|
||||
dilithium-aes-6x5 OBJECT IDENTIFIER ::= { dilithium-aes 2 }
|
||||
dilithium-aes-8x7 OBJECT IDENTIFIER ::= { dilithium-aes 3 }
|
||||
|
||||
SphincsPlus OBJECT IDENTIFIER ::= { publicKey 12 }
|
||||
|
||||
SphincsPlus-shake OBJECT IDENTIFIER ::= { SphincsPlus 1 }
|
||||
SphincsPlus-sha2 OBJECT IDENTIFIER ::= { SphincsPlus 2 }
|
||||
SphincsPlus-haraka OBJECT IDENTIFIER ::= { SphincsPlus 3 }
|
||||
|
||||
SphincsPlus-shake-128s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 1 }
|
||||
SphincsPlus-shake-128f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 2 }
|
||||
SphincsPlus-shake-192s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 3 }
|
||||
SphincsPlus-shake-192f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 4 }
|
||||
SphincsPlus-shake-256s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 5 }
|
||||
SphincsPlus-shake-256f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-shake256 6 }
|
||||
|
||||
SphincsPlus-sha2-128s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 1 }
|
||||
SphincsPlus-sha2-128f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 2 }
|
||||
SphincsPlus-sha2-192s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 3 }
|
||||
SphincsPlus-sha2-192f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 4 }
|
||||
SphincsPlus-sha2-256s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 5 }
|
||||
SphincsPlus-sha2-256f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-sha256 6 }
|
||||
|
||||
SphincsPlus-haraka-128s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 1 }
|
||||
SphincsPlus-haraka-128f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 2 }
|
||||
SphincsPlus-haraka-192s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 3 }
|
||||
SphincsPlus-haraka-192f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 4 }
|
||||
SphincsPlus-haraka-256s-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 5 }
|
||||
SphincsPlus-haraka-256f-r3.1 OBJECT IDENTIFIER ::= { SphincsPlus-haraka 6 }
|
||||
|
||||
symmetricKey OBJECT IDENTIFIER ::= { randombit 3 }
|
||||
|
||||
ocbModes OBJECT IDENTIFIER ::= { symmetricKey 2 }
|
||||
|
||||
aes-128-ocb OBJECT IDENTIFIER ::= { ocbModes 1 }
|
||||
aes-192-ocb OBJECT IDENTIFIER ::= { ocbModes 2 }
|
||||
aes-256-ocb OBJECT IDENTIFIER ::= { ocbModes 3 }
|
||||
serpent-256-ocb OBJECT IDENTIFIER ::= { ocbModes 4 }
|
||||
twofish-256-ocb OBJECT IDENTIFIER ::= { ocbModes 5 }
|
||||
camellia-128-ocb OBJECT IDENTIFIER ::= { ocbModes 6 }
|
||||
camellia-192-ocb OBJECT IDENTIFIER ::= { ocbModes 7 }
|
||||
camellia-256-ocb OBJECT IDENTIFIER ::= { ocbModes 8 }
|
||||
|
||||
sivModes OBJECT IDENTIFIER ::= { symmetricKey 4 }
|
||||
|
||||
aes-128-siv OBJECT IDENTIFIER ::= { sivModes 1 }
|
||||
aes-192-siv OBJECT IDENTIFIER ::= { sivModes 2 }
|
||||
aes-256-siv OBJECT IDENTIFIER ::= { sivModes 3 }
|
||||
serpent-256-siv OBJECT IDENTIFIER ::= { sivModes 4 }
|
||||
twofish-256-siv OBJECT IDENTIFIER ::= { sivModes 5 }
|
||||
camellia-128-siv OBJECT IDENTIFIER ::= { sivModes 6 }
|
||||
camellia-192-siv OBJECT IDENTIFIER ::= { sivModes 7 }
|
||||
camellia-256-siv OBJECT IDENTIFIER ::= { sivModes 8 }
|
||||
sm4-128-siv OBJECT IDENTIFIER ::= { sivModes 9 }
|
@ -1,70 +0,0 @@
|
||||
OS Features
|
||||
========================================
|
||||
|
||||
A summary of OS features as defined in ``src/build-data/os``.
|
||||
|
||||
::
|
||||
|
||||
a: aix
|
||||
a: android
|
||||
c: cygwin
|
||||
d: dragonfly
|
||||
e: emscripten
|
||||
f: freebsd
|
||||
g: generic
|
||||
h: haiku
|
||||
h: hpux
|
||||
h: hurd
|
||||
i: ios
|
||||
l: linux
|
||||
l: llvm
|
||||
m: macos
|
||||
m: mingw
|
||||
n: netbsd
|
||||
n: none
|
||||
o: openbsd
|
||||
q: qnx
|
||||
s: solaris
|
||||
u: uwp
|
||||
w: windows
|
||||
|
||||
.. csv-table::
|
||||
:header: "Feature", "a", "a", "c", "d", "e", "f", "g", "h", "h", "h", "i", "l", "l", "m", "m", "n", "n", "o", "q", "s", "u", "w"
|
||||
|
||||
"alloc_conceal", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " "
|
||||
"apple_keychain", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"arc4random", " ", "X", " ", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", " ", "X", " ", "X", " ", " ", " ", " "
|
||||
"atomics", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X"
|
||||
"auxinfo", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " "
|
||||
"cap_enter", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"ccrandom", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"certificate_store", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", "X"
|
||||
"clock_gettime", "X", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", " "
|
||||
"commoncrypto", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"crypto_ng", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " "
|
||||
"dev_random", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", " ", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", " "
|
||||
"elf_aux_info", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"explicit_bzero", " ", " ", " ", "X", " ", "X", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X", " ", " ", " ", " "
|
||||
"explicit_memset", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " "
|
||||
"filesystem", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X"
|
||||
"getauxval", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"getentropy", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X", " ", "X", " ", " ", " ", "X", " ", "X", " ", " "
|
||||
"getrandom", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"pledge", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " "
|
||||
"posix1", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", " "
|
||||
"posix_mlock", "X", "X", " ", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", " "
|
||||
"prctl", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"proc_fs", "X", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " "
|
||||
"rtlgenrandom", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", "X"
|
||||
"rtlsecurezeromemory", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", "X"
|
||||
"sandbox_proc", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " "
|
||||
"setppriv", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " "
|
||||
"sockets", "X", "X", "X", "X", " ", "X", " ", "X", "X", "X", "X", "X", " ", "X", " ", "X", " ", "X", "X", "X", " ", " "
|
||||
"thread_local", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", " ", "X", "X", "X", "X", "X"
|
||||
"threads", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", " ", "X", "X", "X", "X", "X"
|
||||
"virtual_lock", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", "X"
|
||||
"win32", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X", "X"
|
||||
"winsock2", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", "X"
|
||||
|
||||
.. note::
|
||||
This file is auto generated by ``src/scripts/gen_os_features.py``. Dont modify it manually.
|
@ -1,93 +0,0 @@
|
||||
Reading List
|
||||
================
|
||||
|
||||
These are papers, articles and books that are interesting or useful from the
|
||||
perspective of crypto implementation.
|
||||
|
||||
Papers
|
||||
--------
|
||||
|
||||
Implementation Techniques
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* "Randomizing the Montgomery Powering Ladder"
|
||||
Le, Tan, Tunstall https://eprint.iacr.org/2015/657
|
||||
A variant of Algorithm 7 is used for GF(p) point multplications when
|
||||
BOTAN_POINTGFP_BLINDED_MULTIPLY_USE_MONTGOMERY_LADDER is set
|
||||
|
||||
* "Accelerating AES with vector permute instructions"
|
||||
Mike Hamburg https://shiftleft.org/papers/vector_aes/
|
||||
His public doman assembly code was rewritten into SSS3 intrinsics
|
||||
for aes_ssse3.
|
||||
|
||||
* "Elliptic curves and their implementation" Langley
|
||||
http://www.imperialviolet.org/2010/12/04/ecc.html
|
||||
Describes sparse representations for ECC math
|
||||
|
||||
Random Number Generation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* "On Extract-then-Expand Key Derivation Functions and an HMAC-based KDF"
|
||||
Hugo Krawczyk http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.8254
|
||||
RNG design underlying HMAC_RNG
|
||||
|
||||
AES Side Channels
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* "Software mitigations to hedge AES against cache-based software side
|
||||
channel vulnerabilities" https://eprint.iacr.org/2006/052.pdf
|
||||
|
||||
* "Cache Games - Bringing Access-Based Cache Attacks on AES to Practice"
|
||||
http://www.ieee-security.org/TC/SP2011/PAPERS/2011/paper031.pdf
|
||||
|
||||
* "Cache-Collision Timing Attacks Against AES" Bonneau, Mironov
|
||||
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753
|
||||
|
||||
Public Key Side Channels
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* "Fast Elliptic Curve Multiplications Resistant against Side Channel Attacks"
|
||||
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.98.1028&rep=rep1&type=pdf
|
||||
|
||||
* "Resistance against Differential Power Analysis for Elliptic Curve Cryptosystems"
|
||||
Coron http://www.jscoron.fr/publications/dpaecc.pdf
|
||||
|
||||
* "Further Results and Considerations on Side Channel Attacks on RSA"
|
||||
Klima, Rosa https://eprint.iacr.org/2002/071
|
||||
Side channel attacks on RSA-KEM and MGF1-SHA1
|
||||
|
||||
* "Side-Channel Attacks on the McEliece and Niederreiter Public-Key Cryptosystems"
|
||||
Avanzi, Hoerder, Page, and Tunstall https://eprint.iacr.org/2010/479
|
||||
|
||||
* "Minimum Requirements for Evaluating Side-Channel Attack Resistance
|
||||
of Elliptic Curve Implementations" BSI
|
||||
https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Zertifizierung/Interpretationen/AIS_46_ECCGuide_e_pdf.pdf
|
||||
|
||||
Books
|
||||
------
|
||||
|
||||
* "Handbook of Elliptic and Hyperelliptic Curve Cryptography"
|
||||
Cohen and Frey https://www.hyperelliptic.org/HEHCC/
|
||||
An excellent reference for ECC math, algorithms, and side channels
|
||||
|
||||
* "Post-Quantum Cryptography" Bernstein, Buchmann, Dahmen
|
||||
Covers code, lattice, and hash based cryptography
|
||||
|
||||
Standards
|
||||
-----------
|
||||
|
||||
* IEEE 1363 http://grouper.ieee.org/groups/1363/
|
||||
Very influential early in the library lifetime, so a lot of terminology used
|
||||
in the public key (such as "EME" for message encoding) code comes from here.
|
||||
|
||||
* ISO/IEC 18033-2 http://www.shoup.net/iso/std4.pdf
|
||||
RSA-KEM, PSEC-KEM
|
||||
|
||||
* NIST SP 800-108
|
||||
http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf
|
||||
KDF schemes
|
||||
|
||||
* NIST SP 800-90A
|
||||
http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
|
||||
HMAC_DRBG, Hash_DRBG, CTR_DRBG, maybe one other thing?
|
||||
|
@ -1,103 +0,0 @@
|
||||
Release Process and Checklist
|
||||
========================================
|
||||
|
||||
Releases are done quarterly, normally on the second non-holiday Monday
|
||||
of January, April, July and October. A feature freeze goes into effect
|
||||
starting 9 days before the release.
|
||||
|
||||
.. highlight:: shell
|
||||
|
||||
.. note::
|
||||
|
||||
This information is only useful if you are a developer of botan who
|
||||
is creating a new release of the library.
|
||||
|
||||
Pre Release Testing
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Do maintainer-mode builds with Clang and GCC to catch any warnings
|
||||
that should be corrected.
|
||||
|
||||
Other checks which are not in CI:
|
||||
|
||||
- Native compile on FreeBSD x86-64
|
||||
- Native compile on at least one unusual platform (AIX, NetBSD, ...)
|
||||
- Build the website content to detect any Doxygen problems
|
||||
- Test many build configurations (using `src/scripts/test_all_configs.py`)
|
||||
- Build/test SoftHSM
|
||||
|
||||
Confirm that the release notes in ``news.rst`` are accurate and
|
||||
complete and that the version number in ``version.txt`` is correct.
|
||||
|
||||
Tag the Release
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Update the release date in the release notes and change the entry for
|
||||
the appropriate branch in ``readme.rst`` to point to the new release.
|
||||
|
||||
Now check in, and backport changes to the release branch::
|
||||
|
||||
$ git commit readme.rst news.rst -m "Update for 3.8.2 release"
|
||||
$ git checkout release-3
|
||||
$ git merge master
|
||||
$ git tag 3.8.2
|
||||
|
||||
Build The Release Tarballs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The release script is ``src/scripts/dist.py`` and must be run from a
|
||||
git workspace.
|
||||
|
||||
$ src/scripts/dist.py 3.8.2
|
||||
|
||||
One useful option is ``--output-dir``, which specifies where the
|
||||
output will be placed.
|
||||
|
||||
Now do a final build/test of the released tarball.
|
||||
|
||||
The ``--pgp-key-id`` option is used to specify a PGP keyid. If set,
|
||||
the script assumes that it can execute GnuPG and will attempt to
|
||||
create signatures for the tarballs. The default value is ``EFBADFBC``,
|
||||
which is the official signing key. You can use ``--pgp-key-id=none``
|
||||
to avoid creating any signature, though official distributed releases
|
||||
*should not* be released without signatures.
|
||||
|
||||
The releases served on the official site are taken from the contents
|
||||
in a git repository::
|
||||
|
||||
$ git checkout git@botan.randombit.net:/srv/git/botan-releases.git
|
||||
$ src/scripts/dist.py 3.8.2 --output-dir=botan-releases
|
||||
$ cd botan-releases
|
||||
$ sha256sum Botan-3.8.2.tgz >> sha256sums.txt
|
||||
$ git add .
|
||||
$ git commit -m "Release version 3.8.2"
|
||||
$ git push origin master
|
||||
|
||||
A cron job updates the live site every 10 minutes.
|
||||
|
||||
Push to GitHub
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Don't forget to also push tags::
|
||||
|
||||
$ git push origin --tags release-3 master
|
||||
|
||||
Update The Website
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The website content is created by ``src/scripts/website.py``.
|
||||
|
||||
The website is mirrored automatically from a git repository which must be updated::
|
||||
|
||||
$ git checkout git@botan.randombit.net:/srv/git/botan-website.git
|
||||
$ ./src/scripts/website.py --output botan-website
|
||||
$ cd botan-website
|
||||
$ git add .
|
||||
$ git commit -m "Update for 3.8.2"
|
||||
$ git push origin master
|
||||
|
||||
Announce The Release
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Send an email to the botan-announce and botan-devel mailing lists
|
||||
noting that a new release is available.
|
@ -1,314 +0,0 @@
|
||||
Test Framework
|
||||
================
|
||||
|
||||
Botan uses a custom-built test framework. Some portions of it are
|
||||
quite similar to assertion-based test frameworks such as Catch or
|
||||
Gtest, but it also includes many features which are well suited for
|
||||
testing cryptographic algorithms.
|
||||
|
||||
The intent is that the test framework and the test suite evolve
|
||||
symbiotically; as a general rule of thumb if a new function would make
|
||||
the implementation of just two distinct tests simpler, it is worth
|
||||
adding to the framework on the assumption it will prove useful again.
|
||||
Feel free to propose changes to the test system.
|
||||
|
||||
When writing a new test, there are three key classes that are used,
|
||||
namely ``Test``, ``Test::Result``, and ``Text_Based_Test``. A ``Test``
|
||||
(or ``Test_Based_Test``) runs and returns one or more ``Test::Result``.
|
||||
|
||||
Namespaces in Test
|
||||
-------------------
|
||||
|
||||
The test code lives in a distinct namespace (``Botan_Tests``) and all
|
||||
code in the tests which calls into the library should use the
|
||||
namespace prefix ``Botan::`` rather than a ``using namespace``
|
||||
declaration. This makes it easier to see where the test is actually
|
||||
invoking the library, and makes it easier to reuse test code for
|
||||
applications.
|
||||
|
||||
Test Data
|
||||
-----------
|
||||
|
||||
The test framework is heavily data driven. As of this writing, there
|
||||
is about 1 Mib of test code and 17 MiB of test data. For most (though
|
||||
certainly not all) tests, it is better to add a data file representing
|
||||
the input and outputs, and run the tests over it. Data driven tests
|
||||
make adding or editing tests easier, for example by writing scripts
|
||||
which produce new test data and output it in the expected format.
|
||||
|
||||
Test
|
||||
--------
|
||||
|
||||
.. cpp:class:: Test
|
||||
|
||||
.. cpp:function:: virtual std::vector<Test::Result> run() = 0
|
||||
|
||||
This is the key function of a ``Test``: it executes and returns a
|
||||
list of results. Almost all other functions on ``Test`` are
|
||||
static functions which just serve as helper functions for ``run``.
|
||||
|
||||
.. cpp:function:: static std::string read_data_file(const std::string& path)
|
||||
|
||||
Return the contents of a data file and return it as a string.
|
||||
|
||||
.. cpp:function:: static std::vector<uint8_t> read_binary_data_file(const std::string& path)
|
||||
|
||||
Return the contents of a data file and return it as a vector of
|
||||
bytes.
|
||||
|
||||
.. cpp:function:: static std::string data_file(const std::string& what)
|
||||
|
||||
An alternative to ``read_data_file`` and ``read_binary_file``,
|
||||
use only as a last result, typically for library APIs which
|
||||
themselves accept a filename rather than a data blob.
|
||||
|
||||
.. cpp:function:: static bool run_long_tests() const
|
||||
|
||||
Returns true if the user gave option ``--run-long-tests``. Use
|
||||
this to gate particularly time-intensive tests.
|
||||
|
||||
.. cpp:function:: static Botan::RandomNumberGenerator& rng()
|
||||
|
||||
Returns a reference to a fast, not cryptographically secure
|
||||
random number generator. It is deterministicly seeded with the
|
||||
seed logged by the test runner, so it is possible to reproduce
|
||||
results in "random" tests.
|
||||
|
||||
Tests are registered using the macro ``BOTAN_REGISTER_TEST`` which
|
||||
takes 2 arguments: the name of the test and the name of the test class.
|
||||
For example given a ``Test`` instance named ``MyTest``, use::
|
||||
|
||||
BOTAN_REGISTER_TEST("mytest", MyTest);
|
||||
|
||||
All test names should contain only lowercase letters, numbers, and
|
||||
underscore.
|
||||
|
||||
Test::Result
|
||||
-------------
|
||||
|
||||
.. cpp:class:: Test::Result
|
||||
|
||||
A ``Test::Result`` records one or more tests on a particular topic
|
||||
(say "AES-128/CBC" or "ASN.1 date parsing"). Most of the test functions
|
||||
return true or false if the test was successful or not; this allows
|
||||
performing conditional blocks as a result of earlier tests::
|
||||
|
||||
if(result.test_eq("first value", produced, expected))
|
||||
{
|
||||
// further tests that rely on the initial test being correct
|
||||
}
|
||||
|
||||
Only the most commonly used functions on ``Test::Result`` are documented here,
|
||||
see the header ``tests.h`` for more.
|
||||
|
||||
.. cpp:function:: Test::Result(const std::string& who)
|
||||
|
||||
Create a test report on a particular topic. This will be displayed in the
|
||||
test results.
|
||||
|
||||
.. cpp:function:: bool test_success()
|
||||
|
||||
Report a test that was successful.
|
||||
|
||||
.. cpp:function:: bool test_success(const std::string& note)
|
||||
|
||||
Report a test that was successful, including some comment.
|
||||
|
||||
.. cpp:function:: bool test_failure(const std::string& err)
|
||||
|
||||
Report a test failure of some kind. The error string will be logged.
|
||||
|
||||
.. cpp:function:: bool test_failure(const std::string& what, const std::string& error)
|
||||
|
||||
Report a test failure of some kind, with a description of what failed and
|
||||
what the error was.
|
||||
|
||||
.. cpp:function:: void test_failure(const std::string& what, const uint8_t buf[], size_t buf_len)
|
||||
|
||||
Report a test failure due to some particular input, which is provided as
|
||||
arguments. Normally this is only used if the test was using some
|
||||
randomized input which unexpectedly failed, since if the input is
|
||||
hardcoded or from a file it is easier to just reference the test number.
|
||||
|
||||
.. cpp:function:: bool test_eq(const std::string& what, const std::string& produced, const std::string& expected)
|
||||
|
||||
Compare to strings for equality.
|
||||
|
||||
.. cpp:function:: bool test_ne(const std::string& what, const std::string& produced, const std::string& expected)
|
||||
|
||||
Compare to strings for non-equality.
|
||||
|
||||
.. cpp:function:: bool test_eq(const char* producer, const std::string& what, \
|
||||
const uint8_t produced[], size_t produced_len, \
|
||||
const uint8_t expected[], size_t expected_len)
|
||||
|
||||
Compare two arrays for equality.
|
||||
|
||||
.. cpp:function:: bool test_ne(const char* producer, const std::string& what, \
|
||||
const uint8_t produced[], size_t produced_len, \
|
||||
const uint8_t expected[], size_t expected_len)
|
||||
|
||||
Compare two arrays for non-equality.
|
||||
|
||||
.. cpp:function:: bool test_eq(const std::string& producer, const std::string& what, \
|
||||
const std::vector<uint8_t>& produced, \
|
||||
const std::vector<uint8_t>& expected)
|
||||
|
||||
Compare two vectors for equality.
|
||||
|
||||
.. cpp:function:: bool test_ne(const std::string& producer, const std::string& what, \
|
||||
const std::vector<uint8_t>& produced, \
|
||||
const std::vector<uint8_t>& expected)
|
||||
|
||||
Compare two vectors for non-equality.
|
||||
|
||||
.. cpp:function:: bool confirm(const std::string& what, bool expr)
|
||||
|
||||
Test that some expression evaluates to ``true``.
|
||||
|
||||
.. cpp:function:: template<typename T> bool test_not_null(const std::string& what, T* ptr)
|
||||
|
||||
Verify that the pointer is not null.
|
||||
|
||||
.. cpp:function:: bool test_lt(const std::string& what, size_t produced, size_t expected)
|
||||
|
||||
Test that ``produced`` < ``expected``.
|
||||
|
||||
.. cpp:function:: bool test_lte(const std::string& what, size_t produced, size_t expected)
|
||||
|
||||
Test that ``produced`` <= ``expected``.
|
||||
|
||||
.. cpp:function:: bool test_gt(const std::string& what, size_t produced, size_t expected)
|
||||
|
||||
Test that ``produced`` > ``expected``.
|
||||
|
||||
.. cpp:function:: bool test_gte(const std::string& what, size_t produced, size_t expected)
|
||||
|
||||
Test that ``produced`` >= ``expected``.
|
||||
|
||||
.. cpp:function:: bool test_throws(const std::string& what, std::function<void ()> fn)
|
||||
|
||||
Call a function and verify it throws an exception of some kind.
|
||||
|
||||
.. cpp:function:: bool test_throws(const std::string& what, const std::string& expected, std::function<void ()> fn)
|
||||
|
||||
Call a function and verify it throws an exception of some kind
|
||||
and that the exception message exactly equals ``expected``.
|
||||
|
||||
Text_Based_Test
|
||||
-----------------
|
||||
|
||||
A ``Text_Based_Text`` runs tests that are produced from a text file
|
||||
with a particular format which looks somewhat like an INI-file::
|
||||
|
||||
# Comments begin with # and continue to end of line
|
||||
[Header]
|
||||
# Test 1
|
||||
Key1 = Value1
|
||||
Key2 = Value2
|
||||
|
||||
# Test 2
|
||||
Key1 = Value1
|
||||
Key2 = Value2
|
||||
|
||||
.. cpp:class:: VarMap
|
||||
|
||||
An object of this type is passed to each invocation of the text-based test.
|
||||
It is used to access the test variables. All access takes a key, which is
|
||||
one of the strings which was passed to the constructor of ``Text_Based_Text``.
|
||||
Accesses are either required (``get_req_foo``), in which case an exception is
|
||||
throwing if the key is not set, or optional (``get_opt_foo``) in which case
|
||||
the test provides a default value which is returned if the key was not set
|
||||
for this particular instance of the test.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> get_req_bin(const std::string& key) const
|
||||
|
||||
Return a required binary string. The input is assumed to be hex encoded.
|
||||
|
||||
.. cpp:function:: std::vector<uint8_t> get_opt_bin(const std::string& key) const
|
||||
|
||||
Return an optional binary string. The input is assumed to be hex encoded.
|
||||
|
||||
.. cpp:function:: std::vector<std::vector<uint8_t>> get_req_bin_list(const std::string& key) const
|
||||
|
||||
.. cpp:function:: Botan::BigInt get_req_bn(const std::string& key) const
|
||||
|
||||
Return a required BigInt. The input can be decimal or (with "0x" prefix) hex encoded.
|
||||
|
||||
.. cpp:function:: Botan::BigInt get_opt_bn(const std::string& key, const Botan::BigInt& def_value) const
|
||||
|
||||
Return an optional BigInt. The input can be decimal or (with "0x" prefix) hex encoded.
|
||||
|
||||
.. cpp:function:: std::string get_req_str(const std::string& key) const
|
||||
|
||||
Return a required text string.
|
||||
|
||||
.. cpp:function:: std::string get_opt_str(const std::string& key, const std::string& def_value) const
|
||||
|
||||
Return an optional text string.
|
||||
|
||||
.. cpp:function:: size_t get_req_sz(const std::string& key) const
|
||||
|
||||
Return a required integer. The input should be decimal.
|
||||
|
||||
.. cpp:function:: size_t get_opt_sz(const std::string& key, const size_t def_value) const
|
||||
|
||||
Return an optional integer. The input should be decimal.
|
||||
|
||||
.. cpp:class:: Text_Based_Test : public Test
|
||||
|
||||
.. cpp:function:: Text_Based_Test(const std::string& input_file, \
|
||||
const std::string& required_keys, \
|
||||
const std::string& optional_keys = "")
|
||||
|
||||
This constructor is
|
||||
|
||||
.. note::
|
||||
The final element of required_keys is the "output key", that is
|
||||
the key which signifies the boundary between one test and the next.
|
||||
When this key is seen, ``run_one_test`` will be invoked. In the
|
||||
test input file, this key must always appear least for any particular
|
||||
test. All the other keys may appear in any order.
|
||||
|
||||
.. cpp:function:: Test::Result run_one_test(const std::string& header, \
|
||||
const VarMap& vars)
|
||||
|
||||
Runs a single test and returns the result of it. The ``header``
|
||||
parameter gives the value (if any) set in a ``[Header]`` block.
|
||||
This can be useful to distinguish several types of tests within a
|
||||
single file, for example "[Valid]" and "[Invalid]".
|
||||
|
||||
.. cpp:function:: bool clear_between_callbacks() const
|
||||
|
||||
By default this function returns ``false``. If it returns
|
||||
``true``, then when processing the data in the file, variables
|
||||
are not cleared between tests. This can be useful when several
|
||||
tests all use some common parameters.
|
||||
|
||||
Test Runner
|
||||
-------------
|
||||
|
||||
If you are simply writing a new test there should be no need to modify
|
||||
the runner, however it can be useful to be aware of its abilities.
|
||||
|
||||
The runner can run tests concurrently across many cores. By default single
|
||||
threaded execution is used, but you can use ``--test-threads`` option to
|
||||
specify the number of threads to use. If you use ``--test-threads=0`` then
|
||||
the runner will probe the number of active CPUs and use that (but limited
|
||||
to at most 16). If you want to run across many cores on a large machine,
|
||||
explicitly specify a thread count. The speedup is close to linear.
|
||||
|
||||
The RNG used in the tests is deterministic, and the seed is logged for each
|
||||
execution. You can cause the random sequence to repeat using ``--drbg-seed``
|
||||
option.
|
||||
|
||||
.. note::
|
||||
Currently the RNG is seeded just once at the start of execution. So you
|
||||
must run the exact same sequence of tests as the original test run in
|
||||
order to get reproducible results.
|
||||
|
||||
If you are trying to track down a bug that happens only occasionally, two very
|
||||
useful options are ``--test-runs`` and ``--abort-on-first-fail``. The first
|
||||
takes an integer and runs the specified test cases that many times. The second
|
||||
causes abort to be called on the very first failed test. This is sometimes
|
||||
useful when tracing a memory corruption bug.
|
@ -1,160 +0,0 @@
|
||||
Todo List
|
||||
========================================
|
||||
|
||||
Feel free to take one of these on if it interests you. Before starting
|
||||
out on something, send an email to the dev list or open a discussion
|
||||
ticket on GitHub to make sure you're on the right track.
|
||||
|
||||
Request a new feature by opening a pull request to update this file.
|
||||
|
||||
New Ciphers/Hashes/MACs
|
||||
----------------------------------------
|
||||
* GCM-SIV (RFC 8452)
|
||||
* EME* tweakable block cipher (https://eprint.iacr.org/2004/125)
|
||||
* PMAC
|
||||
* SIV-PMAC
|
||||
* Threefish-1024
|
||||
* Skein-MAC
|
||||
* FFX format preserving encryption (NIST 800-38G)
|
||||
* Adiantum (https://eprint.iacr.org/2018/720)
|
||||
* HPKE (draft-irtf-cfrg-hpke)
|
||||
* Blake3
|
||||
|
||||
Improved Ciphers Implementations
|
||||
----------------------------------------
|
||||
|
||||
* Stiched AES/GCM mode for CPUs supporting both AES and CLMUL
|
||||
* Combine AES-NI, ARMv8 and POWER AES implementations (as already done for CLMUL)
|
||||
* Support for VAES (Zen4/Ice Lake)
|
||||
* NEON/VMX support for the SIMD based GHASH
|
||||
* Vector permute AES only supports little-endian systems; fix for big-endian
|
||||
* SM4 using AES-NI (https://github.com/mjosaarinen/sm4ni) or vector permute
|
||||
* Poly1305 using AVX2
|
||||
* SHA-512 using BMI2+AVX2
|
||||
* Constant time bitsliced DES
|
||||
* SIMD evaluation of SHA-2 and SHA-3 compression functions
|
||||
* Improved Salsa implementations (SIMD_4x32 and/or AVX2)
|
||||
* Add CLMUL/PMULL implementations for CRC24/CRC32
|
||||
|
||||
Public Key Crypto, Math
|
||||
----------------------------------------
|
||||
|
||||
* Short vector optimization for BigInt
|
||||
* Abstract representation of ECC point elements to allow specific
|
||||
implementations of the field arithmetic depending upon the curve.
|
||||
* Curves for pairings (BLS12-381)
|
||||
* Identity based encryption
|
||||
* Paillier homomorphic cryptosystem
|
||||
* New PAKEs (pending CFRG bakeoff results)
|
||||
* New post quantum schemes (pending NIST contest results)
|
||||
* SPHINX password store (https://eprint.iacr.org/2018/695)
|
||||
* X448 and Ed448
|
||||
|
||||
Utility Functions
|
||||
------------------
|
||||
|
||||
* Make Memory_Pool more concurrent (currently uses a global lock)
|
||||
* Guarded integer type to prevent overflow bugs
|
||||
|
||||
External Providers, Hardware Support
|
||||
----------------------------------------
|
||||
|
||||
* Add support ARMv8.4-A SHA-512, SHA-3, SM3 and RNG
|
||||
* Aarch64 inline asm for BigInt
|
||||
* /dev/crypto provider (ciphers, hashes)
|
||||
* Windows CryptoNG provider (ciphers, hashes)
|
||||
* Extend Apple CommonCrypto provider (HMAC, CMAC, RSA, ECDSA, ECDH)
|
||||
* Add support for iOS keychain access
|
||||
* POWER8 SHA-2 extensions (GH #1486 + #1487)
|
||||
* Add support VPSUM on big-endian PPC64 (GH #2252)
|
||||
* Better TPM support: NVRAM, PCR measurements, sealing
|
||||
* Add support for TPM 2.0 hardware
|
||||
|
||||
TLS
|
||||
----------------------------------------
|
||||
|
||||
* Make DTLS support optional at build time
|
||||
* Improve/optimize DTLS defragmentation and retransmission
|
||||
* Make RSA optional at build time
|
||||
* Make finite field DH optional at build time
|
||||
* Certificate Transparency extensions
|
||||
* TLS supplemental authorization data (RFC 4680, RFC 5878)
|
||||
* DTLS-SCTP (RFC 6083)
|
||||
|
||||
PKIX
|
||||
----------------------------------------
|
||||
|
||||
* Further tests of validation API (see GH #785)
|
||||
* Test suite for validation of 'real world' cert chains (GH #611)
|
||||
* X.509 policy constraints
|
||||
* OCSP responder logic
|
||||
|
||||
New Protocols / Formats
|
||||
----------------------------------------
|
||||
|
||||
* Noise protocol
|
||||
* ACME protocol
|
||||
* Cryptographic Message Syntax (RFC 5652)
|
||||
* Fernet symmetric encryption (https://cryptography.io/en/latest/fernet/)
|
||||
* RNCryptor format (https://github.com/RNCryptor/RNCryptor)
|
||||
* Age format (https://age-encryption.org/v1)
|
||||
* Useful OpenPGP subset 1: symmetrically encrypted files.
|
||||
Not aiming to process arbitrary OpenPGP, but rather produce
|
||||
something that happens to be readable by `gpg` and is relatively
|
||||
simple to process for decryption. Require AEAD mode (EAX/OCB).
|
||||
* Useful OpenPGP subset 2: Process OpenPGP public keys
|
||||
* Useful OpenPGP subset 3: Verification of OpenPGP signatures
|
||||
|
||||
Cleanups
|
||||
-----------
|
||||
|
||||
* Unicode path support on Windows (GH #1615)
|
||||
* The X.509 path validation tests have much duplicated logic
|
||||
|
||||
New C APIs
|
||||
----------------------------------------
|
||||
|
||||
* PKCS10 requests
|
||||
* Certificate signing
|
||||
* CRLs
|
||||
* Expose TLS
|
||||
* Expose NIST key wrap with padding
|
||||
* Expose secret sharing
|
||||
* Expose deterministic PRNG
|
||||
* base32
|
||||
* base58
|
||||
* DL_Group
|
||||
* EC_Group
|
||||
|
||||
Build/Test
|
||||
----------------------------------------
|
||||
|
||||
* Support hardcoding all test vectors into the botan-test binary
|
||||
so it can run as a standalone item (copied to a device, etc)
|
||||
* Run iOS binary under simulator in CI
|
||||
* Run Android binary under simulator in CI
|
||||
* Run the TPM tests against an emulator
|
||||
(https://github.com/PeterHuewe/tpm-emulator)
|
||||
* Add support for vxWorks
|
||||
|
||||
CLI
|
||||
----------------------------------------
|
||||
|
||||
* Add a ``--completion`` option to dump autocomplete info, write
|
||||
support for autocompletion in bash/zsh.
|
||||
* Refactor ``speed``
|
||||
* Change `tls_server` to be a tty<->socket app, like `tls_client` is,
|
||||
instead of a bogus echo server.
|
||||
* `encrypt` / `decrypt` tools providing password based file encryption
|
||||
* Add ECM factoring
|
||||
* Clone of `minisign` signature utility
|
||||
* Implementation of `tlsdate`
|
||||
* Password store utility
|
||||
* TOTP calculator
|
||||
* Clone of magic wormhole
|
||||
* ACVP client (https://github.com/usnistgov/ACVP)
|
||||
|
||||
Documentation
|
||||
----------------------------------------
|
||||
|
||||
* Always needs help
|
@ -1,131 +0,0 @@
|
||||
|
||||
Project Goals
|
||||
================================
|
||||
|
||||
Botan seeks to be a broadly applicable library that can be used to implement a
|
||||
range of secure distributed systems.
|
||||
|
||||
The library has the following project goals guiding changes. It does not succeed
|
||||
in all of these areas in every way just yet, but it describes the system that is
|
||||
the desired end result. Over time further progress is made in each.
|
||||
|
||||
* Secure and reliable. The implementations must of course be correct and well
|
||||
tested, and attacks such as side channels and fault attacks should be
|
||||
accounted for where necessary. The library should never crash, or invoke
|
||||
undefined behavior, regardless of circumstances.
|
||||
|
||||
* Implement schemes important in practice. It should be practical to implement
|
||||
any real-world crypto protocol using just what the library provides. It is
|
||||
worth some (limited) additional complexity in the library, in order to expand
|
||||
the set of applications which can easily adopt Botan.
|
||||
|
||||
* Ease of use. It should be straightforward for an application programmer to do
|
||||
whatever it is they need to do. There should be one obvious way to perform any
|
||||
operation. The API should be predicable, and follow the "principle of least
|
||||
astonishment" in its design. This is not just a nicety; confusing APIs often
|
||||
result in errors that end up compromising security.
|
||||
|
||||
* Simplicity of design, clarity of code, ease of review. The code should be easy
|
||||
to read and understand by other library developers, users seeking to better
|
||||
understand the behavior of the code, and by professional reviewers looking for
|
||||
bugs. This is important because bugs in convoluted code can easily escape
|
||||
multiple expert reviews, and end up living on for years.
|
||||
|
||||
* Well tested. The code should be correct against the spec, with as close to
|
||||
100% test coverage as possible. All available static and dynamic analysis
|
||||
tools at our disposal should be used, including fuzzers, symbolic execution,
|
||||
and protocol specific tools. Within reason, all warnings from compilers and
|
||||
static analyzers should be addressed, even if they seem like false positives,
|
||||
because that maximizes the signal value of new warnings from the tool.
|
||||
|
||||
* Safe defaults. Policies should aim to be highly restrictive by default, and if
|
||||
they must be made less restrictive by certain applications, it should be
|
||||
obvious to the developer that they are doing something unsafe.
|
||||
|
||||
* Post quantum security. Possibly a practical quantum computer that can break
|
||||
RSA and ECC will never be built, but the future is notoriously hard to predict.
|
||||
It seems prudent to begin designing and deploying systems now which have at
|
||||
least the option of using a post-quantum scheme. Botan provides a conservative
|
||||
selection of algorithms thought to be post-quantum secure.
|
||||
|
||||
* Performance. Botan does not in every case strive to be faster than every other
|
||||
software implementation, but performance should be competitive and over time
|
||||
new optimizations are identified and applied.
|
||||
|
||||
* Support whatever I/O mechanism the application wants. Allow the application to
|
||||
control all aspects of how the network is contacted, and ensure the API makes
|
||||
asynchronous operations easy to handle. This both insulates Botan from
|
||||
system-specific details and allows the application to use whatever networking
|
||||
style they please.
|
||||
|
||||
* Portability to modern systems. Botan does not run everywhere, and we actually
|
||||
do not want it to (see non-goals below). But we do want it to run on anything
|
||||
that someone is deploying new applications on. That includes both major
|
||||
platforms like Windows, Linux, Android and iOS, and also promising new systems
|
||||
such as Fuchsia.
|
||||
|
||||
* Well documented. Ideally every public API would have some place in the manual
|
||||
describing its usage.
|
||||
|
||||
* Useful command line utility. The botan command line tool should be flexible
|
||||
and featured enough to replace similar tools such as ``openssl`` for everyday
|
||||
users.
|
||||
|
||||
Non-Goals
|
||||
-------------------------
|
||||
|
||||
There are goals some crypto libraries have, but which Botan actively does not
|
||||
seek to address.
|
||||
|
||||
* Deep embedded support. Botan requires a heap, C++ exceptions, and RTTI, and at
|
||||
least in terms of performance optimizations effectively assumes a 32 or 64 bit
|
||||
processor. It is not suitable for deploying on, say FreeRTOS running on a
|
||||
MSP430, or smartcard with an 8 bit CPU and 256 bytes RAM. A larger SoC, such
|
||||
as a Cortex-A7 running Linux, is entirely within scope.
|
||||
|
||||
* Implementing every crypto scheme in existence. The focus is on algorithms
|
||||
which are in practical use in systems deployed now, as well as promising
|
||||
algorithms for future deployment. Many algorithms which were of interest
|
||||
in the past but never saw widespread deployment and have no compelling
|
||||
benefit over other designs have been removed to simplify the codebase.
|
||||
|
||||
* Portable to obsolete systems. There is no reason for crypto software to
|
||||
support ancient OS platforms like SunOS or Windows 2000, since these unpatched
|
||||
systems are completely unsafe anyway. The additional complexity supporting
|
||||
such platforms just creates more room for bugs.
|
||||
|
||||
* Portable to every C++ compiler ever made. Over time Botan moves forward to
|
||||
both take advantage of new language/compiler features, and to shed workarounds
|
||||
for dealing with bugs in ancient compilers, allowing further simplifications
|
||||
in the codebase. The set of supported compilers is fixed for each new release
|
||||
branch, for example Botan 2.x will always support GCC 4.8. But a future 3.x
|
||||
release version will likely increase the required versions for all compilers.
|
||||
|
||||
* FIPS 140 validation. The primary developer was (long ago) a consultant with a
|
||||
NIST approved testing lab. He does not have a positive view of the process or
|
||||
results, particularly when it comes to Level 1 software validations. The only
|
||||
benefit of a Level 1 validation is to allow for government sales, and the cost
|
||||
of validation includes enormous amounts of time and money, adding 'checks'
|
||||
that are useless or actively harmful, then freezing the software so security
|
||||
updates cannot be applied in the future. It does force a certain minimum
|
||||
standard (ie, FIPS Level 1 does assure AES and RSA are probably implemented
|
||||
correctly) but this is an issue of interop not security since Level 1 does not
|
||||
seriously consider attacks of any kind. Any security budget would be far
|
||||
better spent on a review from a specialized crypto consultancy, who would look
|
||||
for actual flaws.
|
||||
|
||||
That said it would be easy to add a "FIPS 140" build mode to Botan, which just
|
||||
disabled all the builtin crypto and wrapped whatever the most recent OpenSSL
|
||||
FIPS module exports.
|
||||
|
||||
* Educational purposes. The library code is intended to be easy to read and
|
||||
review, and so might be useful in an educational context. However it does not
|
||||
contain any toy ciphers (unless you count DES and RC4) nor any tools for
|
||||
simple cryptanalysis. Generally the manual and source comments assume previous
|
||||
knowledge on the basic concepts involved.
|
||||
|
||||
* User proof. Some libraries provide a very high level API in an attempt to save
|
||||
the user from themselves. Occasionally they succeed. It would be appropriate
|
||||
and useful to build such an API on top of Botan, but Botan itself wants to
|
||||
cover a broad set of uses cases and some of these involve having pointy things
|
||||
within reach.
|
@ -1,55 +0,0 @@
|
||||
|
||||
Getting Started
|
||||
========================================
|
||||
|
||||
If you need to build the library first, start with :doc:`building`.
|
||||
Some Linux distributions include packages for Botan, so building from
|
||||
source may not be required on your system.
|
||||
|
||||
.. only:: html
|
||||
|
||||
The :ref:`genindex` and :ref:`search` may be useful to get started.
|
||||
|
||||
.. only:: html and website
|
||||
|
||||
You can also download this manual as a `PDF <https://botan.randombit.net/handbook/botan.pdf>`_.
|
||||
|
||||
Examples
|
||||
----------
|
||||
|
||||
Some examples of usage are included in this documentation. However a better
|
||||
source for example code is in the implementation of the
|
||||
`command line interface <https://github.com/randombit/botan/tree/master/src/cli>`_,
|
||||
which was intentionally written to act as practical examples of usage.
|
||||
|
||||
Books and other references
|
||||
----------------------------
|
||||
|
||||
You should have some knowledge of cryptography *before* trying to use
|
||||
the library. This is an area where it is very easy to make mistakes,
|
||||
and where things are often subtle and/or counterintuitive. Obviously
|
||||
the library tries to provide things at a high level precisely to
|
||||
minimize the number of ways things can go wrong, but naive use will
|
||||
almost certainly not result in a secure system.
|
||||
|
||||
Especially recommended are:
|
||||
|
||||
- *Cryptography Engineering*
|
||||
by Niels Ferguson, Bruce Schneier, and Tadayoshi Kohno
|
||||
|
||||
- `Security Engineering -- A Guide to Building Dependable Distributed Systems
|
||||
<https://www.cl.cam.ac.uk/~rja14/book.html>`_ by Ross Anderson
|
||||
|
||||
- `Handbook of Applied Cryptography <http://www.cacr.math.uwaterloo.ca/hac/>`_
|
||||
by Alfred J. Menezes, Paul C. Van Oorschot, and Scott A. Vanstone
|
||||
|
||||
If you're doing something non-trivial or unique, you might want to at
|
||||
the very least ask for review/input at a place such as the
|
||||
`cryptography stack exchange <https://crypto.stackexchange.com/>`_.
|
||||
And (if possible) pay a professional cryptographer or security company
|
||||
to review your design and code.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
@ -1,449 +0,0 @@
|
||||
Botan 2.x to 3.x Migration
|
||||
==============================
|
||||
|
||||
This is a guide on migrating applications from Botan 2.x to 3.0.
|
||||
|
||||
This guide attempts to be, but is not, complete. If you run into a problem while
|
||||
converting code that does not seem to be described here, please open an issue on
|
||||
Github.
|
||||
|
||||
Headers
|
||||
--------
|
||||
|
||||
Many headers have been removed from the public API.
|
||||
|
||||
In some cases, such as ``datastor.h`` or ``tls_blocking.h``, the functionality
|
||||
presented was entirely deprecated, in which case it has been removed.
|
||||
|
||||
In other cases (such as ``loadstor.h`` or ``rotate.h``) the header was really an
|
||||
implementation header of the library and not intended to be consumed as a public
|
||||
API. In these cases the header is still used internally, but not installed for
|
||||
application use.
|
||||
|
||||
However in most cases there is a better way of performing the same operations,
|
||||
which usually works in both 2.x and 3.x. For example, in 3.0 all of the
|
||||
algorithm headers (such as ``aes.h``) have been removed. Instead you should
|
||||
create objects via the factory methods (in the case of AES,
|
||||
``BlockCipher::create``) which works in both 2.x and 3.0
|
||||
|
||||
Build Artifacts
|
||||
---------------
|
||||
|
||||
For consistency with other platforms the DLL is now suffixed with the library's
|
||||
major version on Windows as well.
|
||||
|
||||
TLS
|
||||
---
|
||||
|
||||
Starting with Botan 3.0 TLS 1.3 is supported.
|
||||
This development required a number of backward-incompatible changes to
|
||||
accomodate the protocol differences to TLS 1.2, which is still supported.
|
||||
|
||||
Build modules
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The build module ``tls`` is now internal and contains common TLS helpers. Users
|
||||
have to explicitly enable ``tls12`` and/or ``tls13``. Note that for Botan 3.0 it
|
||||
is not (yet) possible to exclusively enable TLS 1.3 at build time.
|
||||
|
||||
Removed Functionality
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Functionality removed from the TLS implementation includes
|
||||
|
||||
* TLS 1.0, 1.1 and DTLS 1.0
|
||||
* DSA ciphersuites
|
||||
* anonymous ciphersuites
|
||||
* SRP ciphersuites
|
||||
* SEED ciphersuites
|
||||
* Camellia CBC ciphersuites
|
||||
* AES-128 OCB ciphersuites
|
||||
* DHE_PSK ciphersuites
|
||||
* CECPQ1 ciphersuites
|
||||
|
||||
enum classes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The publicly available C++ enums in the TLS namespace are now `enum class` and
|
||||
their member naming scheme was converted from `SHOUTING_SNAKE_CASE` to
|
||||
`CamelCase`.
|
||||
|
||||
Callbacks
|
||||
^^^^^^^^^
|
||||
|
||||
A number of new callbacks were added with TLS 1.3. None of those new callbacks
|
||||
is mandatory to implement by applications, though. Additionally there are a few
|
||||
backward incompatible changes in callbacks that might require attention by some
|
||||
applications:
|
||||
|
||||
tls_record_received() / tls_emit_data()
|
||||
"""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Those callbacks now take `std::span<const uint8_t>` instead of `const uint8_t*`
|
||||
with a `size_t` buffer length.
|
||||
|
||||
tls_session_established()
|
||||
"""""""""""""""""""""""""
|
||||
|
||||
This callback provides a summary of the just-negotiated connection. It used to
|
||||
have a bool return value letting an application decide to store or discard the
|
||||
connection's resumption information. This use case is now provided via:
|
||||
`tls_should_persist_resumption_information()` which might be called more than
|
||||
once for a single TLS 1.3 connection.
|
||||
|
||||
`tls_session_established` is not a mandatory callback anymore but still allows
|
||||
applications to abort a connection given a summary of the negotiated
|
||||
characteristics. Note that this summary is not a persistable `Session` anymore.
|
||||
|
||||
tls_verify_cert_chain()
|
||||
"""""""""""""""""""""""
|
||||
|
||||
The parameter `ocsp_responses`, which was previously
|
||||
`std::shared_ptr<OCSP::Response>`, is now `std::optional<OCSP::Response>`.
|
||||
|
||||
tls_modify_extensions() / tls_examine_extensions()
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
These callbacks now have an additional parameter of type `Handshake_Type` that
|
||||
identify the TLS handshake message the extensions in question are residing in.
|
||||
TLS 1.3 makes much heavier use of such extensions in a wider range of messages
|
||||
to implement core protocol functionality.
|
||||
|
||||
tls_dh_agree() / tls_ecdh_agree() / tls_decode_group_param()
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
These callbacks were used as customization points for the TLS 1.2 key exchange
|
||||
in the TLS client. To allow similar (and more) customizations with the
|
||||
introduction of TLS 1.3, these callbacks were replaced with a more generic
|
||||
approach.
|
||||
|
||||
Key agreement is split into two callbacks, namely `tls_generate_ephemeral_key()`
|
||||
and `tls_ephemeral_key_agreement()`. Those are used in both clients and servers
|
||||
and in all protocol versions. `tls_decode_group_param()` is removed as it became
|
||||
obsolete by the replacement of the other two callbacks.
|
||||
|
||||
Policy
|
||||
^^^^^^
|
||||
|
||||
choose_key_exchange_group()
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
The new parameter `offered_by_peer` identifies the key exchange groups a peer
|
||||
has sent public exchange offerings for (in TLS 1.3 handshakes only).
|
||||
Choosing a key exchange group that is not listed is legal but will result in an
|
||||
additional network round trip (cf. "Hello Retry Request").
|
||||
In TLS 1.2, this vector is always empty and can be ignored.
|
||||
|
||||
session_ticket_lifetime()
|
||||
"""""""""""""""""""""""""
|
||||
|
||||
Now returns `std::chrono::seconds` rather than a bare `uint32_t`.
|
||||
|
||||
Credentials Manager
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
find_cert_chain(), cert_chain() and cert_chain_single_type()
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
These methods now have a `cert_signature_schemes` parameter that identifies
|
||||
a list of signature schemes the peer is willing to accept for signatures
|
||||
in certificates.
|
||||
Notably, this *does not necessarily* mean that the leaf certificate must feature
|
||||
a public key type able to generate one of those schemes.
|
||||
|
||||
private_key_for()
|
||||
"""""""""""""""""
|
||||
|
||||
Applications must now provide a `std::shared_ptr<>` to the requested private key
|
||||
object instead of a raw pointer to better communicate the implementation's
|
||||
life-time expectations of this private key object.
|
||||
|
||||
.. _tls_session_manager_migration:
|
||||
|
||||
Session and Ticket Handling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Old (pre-Botan 3.0) sessions won't load in Botan 3.0 anymore and should be
|
||||
discarded.
|
||||
For applications using `Session_Manager_SQL` or `Session_Manager_SQLite`
|
||||
discarding happens automatically on first access after the update.
|
||||
|
||||
With Botan 3.0 the session manager now is responsible for stateful session
|
||||
handling (backed by a database) and creation and management of stateless session
|
||||
tickets.
|
||||
The latter was previously handled transparently by the TLS implementation itself.
|
||||
|
||||
Therefore, TLS server applications that relied on Botan's default session
|
||||
management implementations (most notably `Session_Manager_SQLite` or
|
||||
`Session_Manager_In_Memory`) are advised to re-evaluate their choice.
|
||||
Have a look at `Session_Manager_Hybrid` to retain support for both stateful and
|
||||
stateless TLS sessions.
|
||||
TLS client applications may safely keep relying on the above-mentioned default
|
||||
implementations.
|
||||
|
||||
Applications implementing their own `Session_Manager` will need to adapt to the
|
||||
new base class API.
|
||||
|
||||
New API of Session Manager
|
||||
""""""""""""""""""""""""""
|
||||
|
||||
TLS 1.3 removed the legacy resumption procedures based on session IDs or session
|
||||
tickets and combined them under the protocol's Pre-Shared Key mechanism.
|
||||
This new approach allows TLS servers to handle sessions both stateless (as
|
||||
self-contained encrypted and authenticated tickets) and stateful (identified
|
||||
with unique database handles).
|
||||
|
||||
To accomodates this flexibility the `Session_Manager` base class API has changed
|
||||
drastically and is now responsible for creation, storage and management of both
|
||||
stateful sessions and stateless session tickets.
|
||||
Sub-classes therefore gain full control over the session ticket's structure and
|
||||
content.
|
||||
|
||||
API details are documented in the class' doxygen comments.
|
||||
|
||||
The Session Object and its Handle
|
||||
"""""""""""""""""""""""""""""""""
|
||||
|
||||
Objects of class `Session` are not aware of their "session ID" or their "session
|
||||
ticket" anymore.
|
||||
Instead, the new class `Session_Handle` encapsulates the session's identifier or
|
||||
ticket and accompanies the `Session` object where necessary.
|
||||
|
||||
Algorithms Removed
|
||||
-------------------
|
||||
|
||||
The algorithms CAST-256, MISTY1, Kasumi, DESX, XTEA, PBKDF1, MCEIES, CBC-MAC,
|
||||
Tiger, CECPQ1, and NewHope have been removed.
|
||||
|
||||
Certificate API shared_ptr
|
||||
----------------------------
|
||||
|
||||
Previously the certificate store used ``shared_ptr<X509_Certificate>`` in
|
||||
various APIs. However starting in 2.4.0, ``X509_Certificate`` itself is a pimpl
|
||||
to a ``shared_ptr``, making the outer shared pointer pointless. In 3.0 the
|
||||
certificate interfaces have changed to just consume and return ``X509_Certificate``.
|
||||
|
||||
All Or Nothing Package Transform
|
||||
----------------------------------
|
||||
|
||||
This code was deprecated and has been removed.
|
||||
|
||||
Exception Changes
|
||||
-------------------
|
||||
|
||||
Several exceptions, mostly ones not used by the library, were removed.
|
||||
|
||||
A few others that were very specific (such as Illegal_Point) were replaced
|
||||
by throws of their immediate base class exception type.
|
||||
|
||||
The base class of Encoding_Error and Decoding_Error changed from
|
||||
Invalid_Argument to Exception. If you are explicitly catching Invalid_Argument,
|
||||
verify that you do not need to now also explicitly catch Encoding_Error and/or
|
||||
Decoding_Error.
|
||||
|
||||
X.509 Certificate Info Access
|
||||
-------------------------------
|
||||
|
||||
Previously ``X509_Certificate::subject_info`` and ``issuer_info`` could be used
|
||||
to query information about extensions. This is not longer the case; instead you
|
||||
should either call a specific function on ``X509_Certificate`` which returns the
|
||||
same information, or lacking that, iterate over the result of
|
||||
``X509_Certificate::v3_extensions``.
|
||||
|
||||
OCSP Response Validation
|
||||
------------------------
|
||||
|
||||
After mitigating CVE-2022-43705 the OCSP response signature validation was refactored.
|
||||
This led to the removal of the `OCSP::Response::check_signature()` method. If you
|
||||
must validate OCSP responses directly in your application please use the new method
|
||||
`OCSP::Response::find_signing_certificate()` and `OCSP::Response::verify_signature()`.
|
||||
|
||||
Use of ``enum class``
|
||||
--------------------------------
|
||||
|
||||
Several enumerations where modified to become ``enum class``, including
|
||||
``DL_Group::Format``, ``CRL_Code``, ``EC_Group_Encoding``, ``Signature_Format``,
|
||||
``Cipher_Dir``, ``TLS::Extension_Code``, ``TLS::Connection_Side``,
|
||||
``TLS::Record_Type``, and ``TLS::Handshake_Type``
|
||||
|
||||
In many cases the enumeration values were renamed from ``SHOUTING_CASE`` to
|
||||
``CamelCase``. In some cases where the enumeration was commonly used by
|
||||
applications (for example ``Signature_Format`` and ``Cipher_Dir``) the old
|
||||
enumeration names are retained as deprecated variants.
|
||||
|
||||
ASN.1 enums
|
||||
---------------
|
||||
|
||||
The enum ``ASN1_Tag`` has been split into ``ASN1_Type`` and ``ASN1_Class``.
|
||||
Unlike ``ASN1_Tag``, these new enums are ``enum class``. The members of the
|
||||
enums have changed from ``SHOUTING_CASE`` to ``CamelCase``, eg ``CONSTRUCTED``
|
||||
is now ``Constructed``.
|
||||
|
||||
Also an important change related to ``ASN1_Tag::PRIVATE``. This enum value was
|
||||
incorrect, and actually was used for explicitly tagged context specific values.
|
||||
Now, ``ASN1_Class::Private`` refers to the correct class, but would lead to a
|
||||
different encoding vs 2.x's ``ASN1_Tag::PRIVATE``. The correct value to use in
|
||||
3.0 to match ``ASN1_Tag::PRIVATE`` is ``ASN1_Class::ExplicitContextSpecific``.
|
||||
|
||||
Cipher Mode Granularity
|
||||
-------------------------
|
||||
|
||||
Previously Cipher_Mode::update_granularity specified the minimum buffer size
|
||||
that must be provided during processing. However the value returned was often
|
||||
much larger than what was strictly required. In particular some modes can easily
|
||||
accept inputs as small as 1 byte, but their update_granularity was much larger
|
||||
to encourage best performance.
|
||||
|
||||
Now update_granularity returns the true minimum value, and the new
|
||||
Cipher_Mode::ideal_granularity returns a value which is a multiple of
|
||||
update_granularity sized for good performance.
|
||||
|
||||
If you are sizing buffers on the basis of update_granularity consider
|
||||
using ideal_granularity instead. Otherwise you may encounter performance
|
||||
regressions due to creating and processing very small buffers.
|
||||
|
||||
"SHA-160" and "SHA1"
|
||||
---------------------
|
||||
|
||||
Previously the library accepted "SHA-160" and "SHA1" alternative names
|
||||
for "SHA-1". This is no longer the case, you must use "SHA-1". Botan
|
||||
2.x also recognizes "SHA-1".
|
||||
|
||||
PointGFp
|
||||
------------
|
||||
|
||||
This type is now named ``EC_Point``
|
||||
|
||||
X509::load_key
|
||||
-------------------
|
||||
|
||||
Previously these functions returned a raw pointer. They now return
|
||||
a std::unique_ptr
|
||||
|
||||
PKCS11_Request::subject_public_key and X509_Certificate::subject_public_key
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
These functions now return a unique_ptr
|
||||
|
||||
choose_sig_format removed
|
||||
---------------------------
|
||||
|
||||
The freestanding functions choose_sig_format have been removed.
|
||||
Use X509_Object::choose_sig_format
|
||||
|
||||
DLIES Constructors
|
||||
--------------------
|
||||
|
||||
Previously the constructors to the DLIES classes took raw pointers,
|
||||
and retained ownership of them. They now consume std::unique_ptrs
|
||||
|
||||
Credentials_Manager::private_key_for
|
||||
-------------------------------------
|
||||
|
||||
Previously this function returned a raw pointer, which the Credentials_Manager
|
||||
implementation had to keep alive "forever", since there was no way for it to
|
||||
know when or if the TLS layer had completed using the returned key.
|
||||
|
||||
Now this function returns std::shared_ptr<Private_Key>
|
||||
|
||||
OID operator+
|
||||
------------------------
|
||||
|
||||
OID operator+ allowed concatenating new fields onto an object identifier. This
|
||||
was not used at all within the library or the tests, and seems of marginal
|
||||
value, so it was removed.
|
||||
|
||||
If necessary in your application, this can be done by retrieving the
|
||||
vector of components from your source OID, push the new element onto the vector
|
||||
and create an OID from the result.
|
||||
|
||||
RSA with "EMSA1" padding
|
||||
-------------------------
|
||||
|
||||
EMSA1 indicates that effectively the plain hash is signed, with no other
|
||||
padding. It is typically used for algorithms like ECSDA, but was allowed for
|
||||
RSA. This is now no longer implemented.
|
||||
|
||||
If you must generate such signatures for some horrible reason, you can pre-hash
|
||||
the message using a hash function as usual, and then sign using a "Raw" padding,
|
||||
which will allow you to sign any arbitrary bits with no preprocessing.
|
||||
|
||||
ECDSA/DSA with "EMSA1" padding
|
||||
---------------------------------
|
||||
|
||||
Previous versions of Botan required using a hash specifier like "EMSA1(SHA-256)"
|
||||
when generating or verifying ECDSA/DSA signatures, with the specified hash. The
|
||||
"EMSA1" was a reference to a now obsolete IEEE standard.
|
||||
|
||||
In Botan 3 the "EMSA1" notation is still accepted, but now also it is possible
|
||||
to simply use the name of the hash, eg "EMSA1(SHA-256)" becomes "SHA-256".
|
||||
|
||||
Signature Algorithm OIDs
|
||||
-----------------------------
|
||||
|
||||
In line with the previous entries, previously Botan used a string like
|
||||
"ECDSA/EMSA1(SHA-256)" to identify the OID 1.2.840.10045.4.3.2. Now it
|
||||
uses the string "ECDSA/SHA-256" instead, and does not recognize the
|
||||
EMSA1 variant at all (for example in ``OID::from_string``).
|
||||
|
||||
Public Key Signature Padding
|
||||
-----------------------------
|
||||
|
||||
In previous versions Botan was somewhat lenient about allowing the application
|
||||
to specify using a hash which was in fact incompatible with the algorithm. For
|
||||
example, Ed25519 signatures are *always* generated using SHA-512; there is no
|
||||
choice in the matter. In the past, requesting using some other hash, say
|
||||
SHA-256, would be silently ignored. Now an exception is thrown, indicating the
|
||||
desired hash is not compatible with the algorithm.
|
||||
|
||||
In previous versions, various APIs required that the application specify the
|
||||
hash function to be used. In most cases this can now be omitted (passing an
|
||||
empty string) and a suitable default will be chosen.
|
||||
|
||||
Discrete Logarithm Key Changes
|
||||
--------------------------------
|
||||
|
||||
Keys based on the discrete logarithm problem no longer derive from the
|
||||
DL_Scheme_PrivateKey and DL_Scheme_PublicKey classes; these classes
|
||||
have been removed.
|
||||
|
||||
Functions to access DL algorithm internal fields (such as the integer value of
|
||||
the private key using ``get_x``) have been removed. If you need access to this
|
||||
information you can use the new ``get_int_field`` function.
|
||||
|
||||
The constructors of the DL scheme private keys have changed. Previously, loading
|
||||
and creating a key used the same constructor, namely one taking arguments
|
||||
``(DL_Group, RandomNumberGenerator&, BigInt x = 0)`` and then the behavior of
|
||||
the constructor depend on if ``x`` was zero (in which case a new key was
|
||||
created) or otherwise if ``x`` was non-zero then it was taken as the private
|
||||
key. Now there are two constructors, one taking a random number generator and a
|
||||
group, which generates a new key, and a second taking a group and an integer,
|
||||
which loads an existing key.
|
||||
|
||||
XMSS Signature Changes
|
||||
------------------------
|
||||
|
||||
The logic to derive WOTS+ private keys from the seed contained in the XMSS
|
||||
private key has been updated according to the recommendations in
|
||||
NIST SP 800-208. While signatures created with old private keys are still valid using
|
||||
the old public key, new valid signatures cannot be created. To still support legacy
|
||||
private XMSS keys, they can be used by passing ``WOTS_Derivation_Method::Botan2x`` to
|
||||
the constructor of the ``XMSS_PrivateKey``.
|
||||
|
||||
Private XMSS keys created this way use the old derivation logic and can therefore
|
||||
generate new valid signatures. It is recommended to use
|
||||
``WOTS_Derivation_Method::NIST_SP800_208`` (default) when creating new XMSS keys.
|
||||
|
||||
Random Number Generator
|
||||
-----------------------
|
||||
|
||||
Fetching a large number of bytes via `randomize_with_input()` from a stateful
|
||||
RNG will now incorporate the provided "input" data in the first request to the
|
||||
underlying DRBG only. This applies to such DRBGs that pose a limit on the number
|
||||
of bytes per request (most notable ``HMAC_DRBG`` with a 64kB default). Botan 2.x
|
||||
(erroneously) applied the input to *all* underlying DRBG requests in such cases.
|
||||
|
||||
Applications that rely on a static seed for deterministic RNG output might
|
||||
observe a different byte stream in such cases. As a workaround, users are
|
||||
advised to "mimick" the legacy behaviour by manually pulling from the RNG in
|
||||
"byte limit"-sized chunks and provide the "input" with each invocation.
|
File diff suppressed because it is too large
Load Diff
@ -1,54 +0,0 @@
|
||||
Notes for Distributors
|
||||
========================
|
||||
|
||||
This document has information for anyone who is packaging copies of Botan for
|
||||
use by downstream developers, such as through a Linux distribution or other
|
||||
package management system.
|
||||
|
||||
Recommended Options
|
||||
------------------------
|
||||
|
||||
In most environments, zlib, bzip2, and sqlite are already installed, so there is
|
||||
no reason to not include support for them in Botan as well. Build with options
|
||||
``--with-zlib --with-bzip2 --with-sqlite3`` to enable these features.
|
||||
|
||||
Set Path to the System CA bundle
|
||||
---------------------------------
|
||||
|
||||
Most Unix/Linux systems maintain a list of trusted CA certificates at some well
|
||||
known path like ``/etc/ssl/certs/ca-certificates.crt`` or
|
||||
``/etc/ssl/cert.pem``. Unfortunately the exact path varies between systems. Use
|
||||
``--system-cert-bundle=PATH`` to set this path. If the option is not used,
|
||||
``configure.py`` tries a list of known locations.
|
||||
|
||||
Set Distribution Info
|
||||
------------------------
|
||||
|
||||
If your distribution of Botan involves creating library binaries, use the
|
||||
configure.py flag ``--distribution-info=`` to set the version of your
|
||||
packaging. For example Foonix OS might distribute its 4th revision of the
|
||||
package for Botan 2.1.3 using ``--distribution-info='Foonix 2.1.3-4'``. The
|
||||
string is completely free-form, since it depends on how the distribution numbers
|
||||
releases and packages.
|
||||
|
||||
Any value set with ``--distribution-info`` flag will be included in the version
|
||||
string, and can read through the ``BOTAN_DISTRIBUTION_INFO`` macro.
|
||||
|
||||
Minimize Distribution Patches
|
||||
------------------------------
|
||||
|
||||
We (Botan upstream) *strongly* prefer that downstream distributions maintain no
|
||||
long-term patches against Botan. Even if it is a build problem which probably
|
||||
only affects your environment, please open an issue on github and include the
|
||||
patch you are using. Perhaps the issue does affect other users, and even if not
|
||||
it would be better for everyone if the library were improved so it were not
|
||||
necessary for the patch to be created in the first place. For example, having to
|
||||
modify or remove a build data file, or edit the makefile after generation,
|
||||
suggests an area where the build system is insufficiently flexible.
|
||||
|
||||
Obviously nothing in the BSD-2 license prevents you from distributing patches or
|
||||
modified versions of Botan however you please. But long term patches by
|
||||
downstream distributors have a tendency to bitrot and sometimes even result in
|
||||
security problems (such as in the Debian OpenSSL RNG fiasco) because the patches
|
||||
are never reviewed by the library developers. So we try to discourage them, and
|
||||
work to ensure they are never necessary.
|
@ -1,169 +0,0 @@
|
||||
The following PGP key is used to sign all releases:
|
||||
|
||||
pub 2048R/EFBADFBC 2004-10-30
|
||||
Key fingerprint = 621D AF64 11E1 851C 4CF9 A2E1 6211 EBF1 EFBA DFBC
|
||||
uid Botan Distribution Key
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2.0.17 (GNU/Linux)
|
||||
|
||||
mQELBEGD1j0BCADHxPJkPcjJE+4Dlisx2hVc0Dj6JI1MSLrkM8R+2bOhVUSferxP
|
||||
T1EMPhfrAdOHTAloyvRThJztnZsNKqfLL49GGcBLdEGAVNks1pG37Teze5Lx1XIu
|
||||
zJFrozL2sqBy5C6nHpFgd1tcD68Rah2wp0u2cR9owXf1IqKdEfuo661+MTv7wTB1
|
||||
4hKV75nB7ZO6676SEZRILYM+7RJwKAKEmEPJc6hEf94VXn9ecNzaTlHgYkjhz9db
|
||||
LOd3od9XvuUw+LMR1dwBqMxbvR90MiXjbedDEkbArcZB9YOAIvEX/lC3qaW4XJt4
|
||||
iwHWl/YVZEfALcvQywe2CDrH5hO794wd9MpBAAYptBZCb3RhbiBEaXN0cmlidXRp
|
||||
b24gS2V5iQEqBBMBAgAUAhsDAh4BAheABQJKfFpnBBUKCQgACgkQYhHr8e+637xk
|
||||
PQf/aOi78XenwwvFrwXOVIVTdZIf8rK1zJksf26h09UD8uVV6z5iiTcpn86+eN9p
|
||||
6Ar8IH3tD+JuFnPSwZ/r9MNC2XZwenYo4Gb14jqM6/9hBe328vmeM4Y1G7bD4HrL
|
||||
kgV5WEyokqm3zbp3FBLr3Vh68TAC5JB9aHevra+cCA2u3vBNI3YUM5z4TdO150P3
|
||||
J00whkqImQEUni8bgxvllBLFM+uhucsX3HZWkoDEpotbg8yd0bqMkiPEyMr1OnJq
|
||||
eDVDMrB5wnyLgLFfRAAw3mopM0C1PNOAHr/BIYiaDHX2OwnOfep8rMDoRVf2Ge0D
|
||||
DBgsJJ6LduQHLeg403SHWL2F6YkCHAQTAQIABgUCQYPWUgAKCRBcD5boTsFta+r9
|
||||
EACWVis7YcaGkKKgRB/5ox8rM36XVhMXdh/hnnGHt5rapbbRRkRHRcWU8WIcFO1A
|
||||
59+TfwNNd8gN1MEt/5aX5KHWVKHBDexJgIxm6Dm1pisYHf/dnYQPM18hmqqwNlKY
|
||||
97hFkPpHd7enrtc/SvGbQhhLXYlpwBrdMl76e9xJLnnrRQksxegGPo8cr+C9HTs1
|
||||
Lwa8zzBxyBwYBYX+0moDkDShEhuXx6mEOXrGvQanJuIvpoIwGH+62E65MbJGlwWp
|
||||
w/MAtm2jFhBIhGV0bqJCFp9zIgdNgfskBaPr0oilbuJQZqP0Iqe/6CCt4XkS51yW
|
||||
ZqxjLAFpEpvDec4PGw3witKf/koGon9X8C035+nEjLBrWy18Q91vw2USyLI+mm9d
|
||||
iMAS8pY2gomfxBO2VwYHJryZykjCYQkccRA1tHteRj4gqTObo0Ak47y5MnplTWwi
|
||||
40oP7K2cfhCRBmMioxmYES4xsHEupfRBo3xr1Jq9q0t688WTT1NXHPMPoueF9mKZ
|
||||
Cf2pa9aHsqBmWTm3sCaNQKGubCDBEUmJUyndmSatJyYM7NVYoUp6EfqMACFuTNdB
|
||||
sjKMh7aWVikQpbJDfA1BIU3lZeqgjgrghVAWkEOBfhG0IVZj+RVCJpsqoTJ8asY2
|
||||
VreArSCyr/VnLEnfuH/QpgvCiCbepo3E34DJt4SaAOO2ZohGBBARAgAGBQJMGVc1
|
||||
AAoJEKY/LL36AvvMgsoAn2G7kXd09BF7ffk1Sfh174SVrvM9AKC7+R7x0+yV3SCd
|
||||
JkkUOo3xR5cOxw==
|
||||
=1QuR
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
This key can be used to contact the primary maintainer:
|
||||
|
||||
pub rsa3072/57123B60 2015-03-23
|
||||
Key fingerprint = 4E60 C735 51AF 2188 DF0A 5A62 78E9 8043 5712 3B60
|
||||
uid Jack Lloyd <jack@randombit.net>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQGNBFUQXRMBDACZJvcSkr+GNDtIdP9fQWRXByriiIKvuKbqU8KGdhTcPeKwl3y3
|
||||
l1W9XsWA2DJ8QDKo4ZcV0lycszIvwBLZllJJWSVNFKxJK2IW33xcIo9dhNqj+hcz
|
||||
LxKtBlBU3QKXdQ9+VKSY4EpO6gt/ar21PV+EQcFA9UtT1mRKVqY0pGGxqfQjrOss
|
||||
rJKoJyA+1trH4ir7+0/524HNzsBj3B1GmrYfstspqetXyVQ1DoFiThUnj/zJGes5
|
||||
uW9laI9VBgrtMTBbYrylBytXiF0Flzx+bd21krgL37NH2uU0EHPjSx571q/XGG2U
|
||||
4iOEPvPu7vtV8Rpqd0xQyaHcpoHNklcfND1c/6uZG1Sx9atDScRYHinUZvtTRtN+
|
||||
OY5vW+H7LJqT6CeMjh6Ev53V+0JCDZFQLaBdP/NanSQBUhPkyfyQSiqWOSuaMD6n
|
||||
Eu+BigmzwDlsauuReTJ65gdIGI9Egt7Ax/ooKpBvPkWeT+GORKTs+qGy6sbKXrTe
|
||||
crFFN/HZPWAJ+c8AEQEAAbQfSmFjayBMbG95ZCA8amFja0ByYW5kb21iaXQubmV0
|
||||
PokB0QQTAQoAOwIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgBYhBE5gxzVRryGI
|
||||
3wpaYnjpgENXEjtgBQJlIUveAhkBAAoJEHjpgENXEjtg9d0L/iMxl7bVhwrRNUDo
|
||||
fdxZoCVPqPBnA29uiwN4Ff8VIr5yiA39DYAD14PoQN8+mVc9+0P5ersLanszSg7b
|
||||
ZMLd1s39Ryydy2YfXqk9jHlDOFpsimknAd+NEYYPrRTQ+dybk9qoL/qeNxZl7Oig
|
||||
/GyMS96I9PDHLx43gBe4OsIe+QB2ulgVTMIDwnMyeuaIDRmL+w4+caTxKBj4fwtV
|
||||
3SN1VSugEV1Uli0Ofk1yp+NsEIVyOJCi7mV/KLmffdAMqSoBnHZvNqz65i4Tt2mV
|
||||
PvEb5Xvh5E4HBGLCFNj5XEFZmWvjOhkx7XyaJBqHS2I3j/JWGhpLDXwITlpQLBMi
|
||||
ssstlL4ju+STOCfGWDQjOxFGelgbjD54Pu2N/TlidT5FORLguR0Eqtb0A6gYybNh
|
||||
UY/dJqbSPegd9xFWszrnO5o7sV3O1x5oWIOkEi/IYhy9SschPPi3m5RI7qJt6PRI
|
||||
TfF5IBx9GQQtDnrQnbCHB3+BkVuixbEOORmYxm1sR79NE8UTerQgSmFjayBMbG95
|
||||
ZCA8bGxveWRAcmFuZG9tYml0Lm5ldD6JARwEEAEIAAYFAlYaUEwACgkQYhHr8e+6
|
||||
37zLeQf+OdP/xE2YyFUJL1+xEKHpvAeN+98Vn1C2sTmotNIaPwVBY9FLeA484IWd
|
||||
FwnJfXx1gQyybxlytz4BZuC7Jzu60OEmk5IFRIqQoVywEXWCOUg/UEBWZm+ZcRzI
|
||||
Fciqj9PcOfpt6s/aSZd5+Rcm5HUGALYCqek2s9nGO8a1Wnk4m9d1u/RAGlxFM2th
|
||||
e1v5p597ItGhcOP3tjWVPPOuTe0E+/FI3ZxpotKGdfS6F/GB2bP7kma2iVO621Cs
|
||||
9wsYmrZEamKpax7X7p9myaAG0YRdCTslFd/EOTLOllPhy58DTr7qyswBPEI0x8WE
|
||||
DTE0G0IdQYNmLq4kuzeOaIlcUMULzYkBuQQTAQIAIwUCVRBdEwIbAwcLCQgHAwIB
|
||||
BhUIAgkKCwQWAgMBAh4BAheAAAoJEHjpgENXEjtgjxoL/0ZjgM16mq2imrViVjVe
|
||||
u3IuDe0bMq8lUdfDTuQZmK68U5hclwPO4qEVoa4grEn7s++t45fJwP/39YVfILC+
|
||||
FzMyBtF/eUWqSNB2a+fCYgZR9kvemqiskN1KMqJpeTz80kEQEeVM3X31sUQJPMGv
|
||||
jyR4YevNQ9RiHZTfCjwI1blmwcceaJuN6g6l90uAr52dQ3A6Tf+cRm1ZR31xPAKd
|
||||
3m/LG3sjWnWe1vcksAR3jPnB3Zp8kduNBne6JNAFcNR3U8Ufojp8jsv5R5T60Y09
|
||||
7d97ob7M2HGYk8oE8TDNMD+vqK4utDA0Edg9ibon98oENTXXsefC7Phb1FJVWu2L
|
||||
MJYhtroSm0V6dyKCu4Ido7gJZsWXvUK7yfqJsQg0d0qkT2pDNIPmQd/CwnoVWeX1
|
||||
CTzImqH1Ts0X8LyEctukX0nmfhZ83epnIWlQxuwRWnpGG/85ufHBqo1hYKoLKIJr
|
||||
Cw2T/+Szhev4eZ48ndcD2XO+BUKgwStr6fVFscIQYialSYkB0AQTAQoAOgIbAwcL
|
||||
CQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAFiEETmDHNVGvIYjfClpieOmAQ1cSO2AF
|
||||
AmUhSvkACgkQeOmAQ1cSO2A22QwAk8/mcCQOeBn8mHgeoYiaSTW1JoIC0fIagMPh
|
||||
hp2eAbPofk/I3L443t31Ye4YSMjqF7YiyNo063qBBQoyok4kT3hftnIrml8CwIO0
|
||||
33pREPKg3dgU/t+4cOIFlBYiCYn5T3SLjGAL5vlxzTmSKX1Xu79uo+EKa7G2u5hM
|
||||
Gpz5rDXkPgSyZ19/uDu+01CG+JlwHgwOh8bZQSu0/Jg8Qu0ecc87ENpR+eFXqlSL
|
||||
hzdYJ6XPTC6RN/LQFLxTcR8TQ15ThRK6LEocZadg1kJDeadcdM8aRYPI2S7aLCha
|
||||
MnqUzckYdDSW40Bsg0PdxNKTDSBoa7vPbDMR/XkAd03bRGzdezxbr7m7SHOzjnmY
|
||||
SXhAlnkVH6ouSM0GFarWqIeMe6isDiKX8LKdWNySEiMuSuTz2KX15ZedOcYPksdb
|
||||
DfC0tuQUL6O3plsIGJWy9fVOrLnW6D+P77AlHQsRe7OxlFo3Jhsf4FdsD4cLXVN4
|
||||
r/fngFYkokBOv3rGp+aXcEF5uYKAtCFKYWNrIExsb3lkIDxqYWNrLmxsb3lkQGdt
|
||||
YWlsLmNvbT6JAc4EEwEKADgCGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AWIQRO
|
||||
YMc1Ua8hiN8KWmJ46YBDVxI7YAUCZSFK4QAKCRB46YBDVxI7YGvdC/4jdtd4Qfo2
|
||||
i4VUmOrjJ1sFiSehutOCsTAweDDyqUjxmXaMLOlPAeVp9Nq/kUtO4qtLac5sRBxX
|
||||
KigxjrBYJpBq0cK9nYnMEHdX86uXhfvclFQIxzvwkC3pYQgZcD9XfduUTiJeNGrh
|
||||
mQbyopcfbKzv3Q5j4v1H4s61L3LySIDxvZYvzgQEcCrG89+gxlsG2eWMuPySBICE
|
||||
skEAe/2rLuGKcSSFTJXpVAkB9r8o9cOHSw63BydvL5o1T1KeDs4cZD1KUlJ2VaBf
|
||||
W1IoaXynUIHcti1h8iHWNifirgtSRSezz5/G3JeQ8cUSyC4bkMXmQulrHUUCuhZ6
|
||||
GxqtxAEQ8rUrNV8G9xZrU0VP1un3c0RGS4kz2IKa1uk1FEnxDa6YQaExwrHbWzR0
|
||||
8YX1zl7/lekdE1tjRrqIdpzu84MiLHraEvX5agrbdv3F59cJB5lYTXsYaX/8rgus
|
||||
AFdFAQA87MfUKVo38fBZF4BKFu8goGUP7UeGIuZGExavIAjzQkDrUwO5AY0EVRBd
|
||||
EwEMAN6NE/fR/Ours4jc6SaVocKSZ+/pGXVrxQ/ZFoba7kJq09DLQZ21vHYkq7wM
|
||||
rAta9D6gH5bLZ90xI6ScyR9fYTWYDXdDHx8Sg7Mj3ZKhxjr1tQicRPT6BP4WLqBI
|
||||
CdlUWV//OCRFk13G8feDO+ZT8YP/dVUrj3n9/mwfOHm7Npb7PHX/LFuDyo/1EXZZ
|
||||
yqw3/LlI+z+1uBKFYD2WqzLw8Sm/U+ajzP6y04wUkf45VjLkFI2bPk6CVYNt2TvO
|
||||
EzIO3zBAN6DSLSFOTYn9UwR2vrpvoJsDjjSRjcjbZ/8uFCWfLhgTwMeQcH0jxHr4
|
||||
7Qs2coApHBAIB57eS6Z/y4Vja3Y0ANpb51Fu7MDPXQXW4g89GMTIEKu2/KUN/onG
|
||||
IYh6Js9RYNf8SJ+waQ0NULXAMk1AAfknl2Apl9gKRDH6EvevQXPVI6ElOTZw4gqG
|
||||
z9xGqC+gbmh2UmS5n8B/nK2d0AMN+1elZAapTFFdOMhMdDeBk+1GRQ/t/zsLTUPS
|
||||
SRVLFwARAQABiQGfBBgBAgAJBQJVEF0TAhsMAAoJEHjpgENXEjtg3rgMAIDJgnuE
|
||||
Y7neuJMIzHyO59a8X+9ip9XfeDNwjaqJk0rIoqSdkIqjG8I6C4lbeL0pnGzliudv
|
||||
EmQij4hnSNfOUk58oGyRdyUeK9eC2KeZ+Hs3sqMuAhlYIh+RR6ifo5kqxR/geo6i
|
||||
XKS8VqDQRiqoSSrLqhIU7kQiFcQWc3wYaSOUXNpZzvlTlMYM4qP9Yrzu8dG1tKST
|
||||
3fmWi8l9/TmHIPtskgB0dzTdkKe2kZpJFFquYtorWtCQwF+wmtA02NMHwrQzwh/R
|
||||
qNz9wUEwhQVBa/A8p0wdEskLFQZXt3PnY8GHQVz59tArolw3kes0/VrtgCUFS7tv
|
||||
mn9xI6lJxveQiN6Ec2z5gbwKBShkSvopi0g83YLeSNPrCIBmLSCOm1AjsXF3sQaz
|
||||
EYqAGhB6qibCsuebxnprq8Qa/j0wsq7n8ZO7a6cdcnhu4fF3YdWcaWlCUKzzWb8W
|
||||
XXoeCaOKxmD5IgsGiAxnPKvsBge1rMhlCoJJhJEmUlwxoP67Nt2mHbYh/Q==
|
||||
=4XG/
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
This key is used for signing git commits:
|
||||
|
||||
pub rsa2048 2016-03-03 [SC] [expires: 2028-03-01]
|
||||
117510149DF418ABD19CB06D9FFD596FAB50F90D
|
||||
uid Jack Lloyd (Git Signing Key) <jack@randombit.net>
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFbYWi4BCACjgz3gYgWMybPLiovNLnLonG0ex2y9kJgsR+Pm08L2fwCVCaHx
|
||||
wjlK5Oq04x3bvujZk7P0TThqS1WonYtEiVxz3Hcvt7rlU5fSCj/1uYmZV+mbPBdY
|
||||
f/yXMx3UD1UkZrdzbM21L78dfOoLZ2ybyuk4QOEad/AkouDCUA2pY3DJdNyX8Aee
|
||||
dBdQ+sQqF6DyDz4SDY+KAq3nFmmT04bdkiL9sZb2HUokxIdeA6HIR+CxxFaZzrYW
|
||||
Ky4iNPS1Zxv5D1KmpZzUOfN9RTgkbdRltgWxjpB+DFNUkpu3hYm/Y9lTPqGBt2C8
|
||||
JfIS5OaHxUVz0A+DtIGy+lk8/O5ek4suQBZ3ABEBAAG0MUphY2sgTGxveWQgKEdp
|
||||
dCBTaWduaW5nIEtleSkgPGphY2tAcmFuZG9tYml0Lm5ldD6JAVcEEwEIAEECGwMF
|
||||
CwkIBwIGFQgJCgsCBBYCAwECHgECF4ACGQEWIQQRdRAUnfQYq9GcsG2f/Vlvq1D5
|
||||
DQUCZAH4lgUJFo+f6AAKCRCf/Vlvq1D5DfCYB/0TXJ9WuuL5cgXJLK6IyvrlJJvp
|
||||
mncY2PDzfscgO8jWLGfnhOO/Fiy6JvSXmllgNiSufNbaaq3c9wx+qXY7qqUbwiM8
|
||||
w0bokFyVCbIc+Y7d7q359mdFFx0U8NWuQStkeGQ7GcckMLZ2rftY4fyBgeL0MiuH
|
||||
YpzWpFgvmllB+vVniHAh79VMQqnR42Y7r6W5XWYmz6AmpBlI7IOLY272k6nyu7Qr
|
||||
SGlKVU3XctvKS8RAEqvD6CSbls9tXcEZ9XEcOxvUPAgb+NRN7aXbHed3eE8s4NBY
|
||||
Z2vPDgPBCQ423PRnB+McFVHA+N7fdMGOcxkkDi0F1DcgSAcyMuiJFns88BKgiQE9
|
||||
BBMBCAAnBQJYD2ybAhsDBQkHhM4ABQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJ
|
||||
EJ/9WW+rUPkNXfIIAIOgepYeZN2HL2T3A8pk+5JR2cfBoRufYgnG6mVHPejgZDW+
|
||||
9PH1tPDgidnePw3/jfD1oskt1VwOCkqaSBAcG2QeOBEklcsrQuvOfW7B7XFydYGw
|
||||
T9Fm8/sxekiGjDQQWQEEH4j3Vt1GlI2sJrpqMe/WMXISsEnLfw0kDspUSlFOn8oy
|
||||
rBU9Pd8KaSi38lp05a9Mcun5enJ3JpQHQ5RlNXDNh/Sn9NZ+MKWggytZqIy82jnv
|
||||
6zo0raZDup4hLKopjen/SINR5XcwRK2lUtYVwwQH8FHG9IkeVJNWJkVCdZLB08sq
|
||||
4WHRbtVjy6mpvEHTmolAtHjLSiV5W50LDKLwX260MkphY2sgTGxveWQgKEdpdCBT
|
||||
aWduaW5nIEtleSkgPGxsb3lkQHJhbmRvbWJpdC5uZXQ+iQFUBBMBCAA+AhsDBQsJ
|
||||
CAcCBhUICQoLAgQWAgMBAh4BAheAFiEEEXUQFJ30GKvRnLBtn/1Zb6tQ+Q0FAmQB
|
||||
+J0FCRaPn+gACgkQn/1Zb6tQ+Q1DIAgAlR0igunTJjz38Zs9M8rWr5OzeG9Hbkse
|
||||
mClFcH2TPGxLIjI5eMLLjVbxyQkeP2rjaZb/bnuzrohQ5X6Le0LZQA77khFkWpRZ
|
||||
HQ0wDHGSLlLeSD9BiPmhf4drDf8/M+QXA5kTxEHMyKxPsLaOhXYgHPyYQcS3R+H4
|
||||
6jIVmCB5PyYynsSKhFoUiFcBbURApAagaUTf/TGzcaXDGzKkdA6X5g1xlLt+3GTK
|
||||
3aKwOLN7RhMYLz1V6FwblLUYSgpwuAmDfGayNVcBkhK/Qg4yPT0M25H5tLrELh2L
|
||||
fvkeuV29sD3005sI3t+4T4yTCNOCcahaRCaFfUKpyZk7OyUYXRAPaokBnAQQAQgA
|
||||
BgUCVthcNwAKCRB46YBDVxI7YLwrC/95sk2uEyiScbl1I9UmknEvS1r+bgpgGNf3
|
||||
hWwHo5/P3pSac2UJ70TFuLTZ5wvKBB8H1RS/ueys5EY5KggQhX9FJiA3Z5hQzbUM
|
||||
d12WBUbcNNGsb/+JXqvMB2CRl1GTEGGfN4UlG/hMyadFBczbH6COiCcNYumOB2+R
|
||||
EVy/mXp9MfbgiV1x3Kae+aoGawu+qgoWPXcK2wOOeCnmAaCn+J4hbqw+aBBfWkkJ
|
||||
YcUN7/SpyO+7LR8oyrQ7J3T/x1cKc1rA9v/3GVBj6UKkcgt+8WxW3Ll2OoeoM0oQ
|
||||
G5jHI+McgI8ZG6RIr7MJLQQTyfP+jGivg4ivmy9rB8g7lnDr1RKjTWML4rU5JElC
|
||||
2EV+3kapPCR8eeJglJWHsrWs8j8ffm1/5dksHCVp9azu9Bvxdl8A/OGrD1uVzlFL
|
||||
jvyurM1DQXU8chONtpIKQwKBo1rZp5qgjD25COnq4HZPjEYB6qx3ok+uvmDVVkU+
|
||||
q2Fd2IO7omY3hpWSwb9ILHYLC/aqK5I=
|
||||
=fsUW
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -1,43 +0,0 @@
|
||||
|
||||
Development Roadmap
|
||||
========================================
|
||||
|
||||
Near Term Plans
|
||||
----------------------------------------
|
||||
|
||||
Here is an outline for the development plans over the next 12-24 months,
|
||||
as of February 2023.
|
||||
|
||||
Botan 2
|
||||
---------------
|
||||
|
||||
Botan 2 is still supported, but no further feature work is planned.
|
||||
Only security issues and serious bugs will be addressed.
|
||||
|
||||
Botan 3
|
||||
---------------
|
||||
|
||||
The following future work is currently planned for Botan 3:
|
||||
|
||||
* BSI Project 481 [https://github.com/randombit/botan/issues/3108]
|
||||
will add several new post-quantum algorithms including SPHINCS+
|
||||
signatures, LMS signatures, FrodoKEM, and Classic McEliece.
|
||||
|
||||
* New ECC based password authenticated key exchanges, to replace SRP.
|
||||
The most likely candidate algorithms are CPace, OPAQUE, or SPAKE2+.
|
||||
|
||||
* Adding an implementation of BLS12-381 elliptic curve pairing.
|
||||
|
||||
* Low level integer math and elliptic curve arithmetic optimizations.
|
||||
|
||||
Botan 4
|
||||
---------------
|
||||
|
||||
At this time there is no immediate plan for a new major version. When it occurs,
|
||||
it will remove functionality currently marked as deprecated, and adopt a new C++
|
||||
version. This is unlikely to occur before 2026, at the earliest.
|
||||
|
||||
One major change already planned for Botan 4 is that in this release, Public_Key
|
||||
will no longer derive from Private_Key. And similarly, specific private keys
|
||||
(for example RSA_PrivateKey) will no longer derive from their cooresponding
|
||||
public key type.
|
@ -1,390 +0,0 @@
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
Security Advisories
|
||||
========================================
|
||||
|
||||
If you think you have found a security bug in Botan please contact
|
||||
Jack Lloyd (jack@randombit.net). If you would like to encrypt your
|
||||
mail please use::
|
||||
|
||||
pub rsa3072/57123B60 2015-03-23
|
||||
Key fingerprint = 4E60 C735 51AF 2188 DF0A 5A62 78E9 8043 5712 3B60
|
||||
uid Jack Lloyd <jack@randombit.net>
|
||||
|
||||
This key can be found in the file ``doc/pgpkey.txt`` or online at
|
||||
https://keybase.io/jacklloyd and on most PGP keyservers.
|
||||
|
||||
2022
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2022-11-16: Failure to correctly check OCSP responder embedded certificate
|
||||
|
||||
OCSP responses for some end entity are either signed by the issuing CA certificate of
|
||||
the PKI, or an OCSP responder certificate that the PKI authorized to sign responses in
|
||||
their name. In the latter case, the responder certificate (and its validation path
|
||||
certificate) may be embedded into the OCSP response and clients must verify that such
|
||||
certificates are indeed authorized by the CA when validating OCSP responses.
|
||||
|
||||
The OCSP implementation failed to verify that an authorized responder certificate
|
||||
embedded in an OCSP response is authorized by the issuing CA. As a result, any valid
|
||||
signature by an embedded certificate passed the check and was allowed to make claims
|
||||
about the revocation status of certificates of any CA.
|
||||
|
||||
Attackers that are in a position to spoof OCSP responses for a client could therefore
|
||||
render legitimate certificates of a 3rd party CA as revoked or even use a compromised
|
||||
(and actually revoked) certificate by spoofing an OCSP-"OK" response. E.g. an attacker
|
||||
could exploit this to impersonate a legitimate TLS server using a compromised
|
||||
certificate of that host and get around the revocation check using OCSP stapling.
|
||||
|
||||
Introduced in 1.11.34, fixed in 2.19.3
|
||||
|
||||
2020
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2020-12-21 (CVE-2021-24115): Codec encoding/decoding was not constant time
|
||||
|
||||
The base64, base32, base58 and hex encoding/decoding routines used lookup
|
||||
tables which could leak information via a cache-based side channel attack.
|
||||
The encoding tables were small and unlikely to be exploitable, but the
|
||||
decoding tables were large enough to cause non-negligible information
|
||||
leakage. In particular parsing an unencrypted PEM-encoded private key within
|
||||
an SGX enclave could be easily attacked to leak key material.
|
||||
|
||||
Identified and reported by Jan Wichelmann, Thomas Eisenbarth,
|
||||
Sebastian Berndt, and Florian Sieck.
|
||||
|
||||
Fixed in 2.17.3
|
||||
|
||||
* 2020-07-05: Failure to enforce name constraints on alternative names
|
||||
|
||||
The path validation algorithm enforced name constraints on the primary DN
|
||||
included in the certificate but failed to do so against alternative DNs which
|
||||
may be included in the subject alternative name. This would allow a corrupted
|
||||
sub-CA which was constrained by a name constraints extension in its own
|
||||
certificate to issue a certificate containing a prohibited DN. Until 2.15.0,
|
||||
there was no API to access these alternative name DNs so it is unlikely that
|
||||
any application would make incorrect access control decisions on the basis of
|
||||
the incorrect DN. Reported by Mario Korth of Ruhr-Universität Bochum.
|
||||
|
||||
Introduced in 1.11.29, fixed in 2.15.0
|
||||
|
||||
* 2020-03-24: Side channel during CBC padding
|
||||
|
||||
The CBC padding operations were not constant time and as a result would leak
|
||||
the length of the plaintext values which were being padded to an attacker
|
||||
running a side channel attack via shared resources such as cache or branch
|
||||
predictor. No information about the contents was leaked, but the length alone
|
||||
might be used to make inferences about the contents. This issue affects TLS
|
||||
CBC ciphersuites as well as CBC encryption using PKCS7 or other similar padding
|
||||
mechanisms. In all cases, the unpadding operations were already constant time
|
||||
and are not affected. Reported by Maximilian Blochberger of Universität
|
||||
Hamburg.
|
||||
|
||||
Fixed in 2.14.0, all prior versions affected.
|
||||
|
||||
2018
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2018-12-17 (CVE-2018-20187): Side channel during ECC key generation
|
||||
|
||||
A timing side channel during ECC key generation could leak information about
|
||||
the high bits of the secret scalar. Such information allows an attacker to
|
||||
perform a brute force attack on the key somewhat more efficiently than they
|
||||
would otherwise. Found by Ján Jančár using ECTester.
|
||||
|
||||
Introduced in 1.11.20, fixed in 2.8.0.
|
||||
|
||||
* 2018-06-13 (CVE-2018-12435): ECDSA side channel
|
||||
|
||||
A side channel in the ECDSA signature operation could allow a local attacker
|
||||
to recover the secret key. Found by Keegan Ryan of NCC Group.
|
||||
|
||||
Bug introduced in 2.5.0, fixed in 2.7.0. The 1.10 branch is not affected.
|
||||
|
||||
* 2018-04-10 (CVE-2018-9860): Memory overread in TLS CBC decryption
|
||||
|
||||
An off by one error in TLS CBC decryption meant that for a particular
|
||||
malformed ciphertext, the receiver would miscompute a length field and HMAC
|
||||
exactly 64K bytes of data following the record buffer as if it was part of the
|
||||
message. This cannot be used to leak information since the MAC comparison will
|
||||
subsequently fail and the connection will be closed. However it might be used
|
||||
for denial of service. Found by OSS-Fuzz.
|
||||
|
||||
Bug introduced in 1.11.32, fixed in 2.6.0
|
||||
|
||||
* 2018-03-29 (CVE-2018-9127): Invalid wildcard match
|
||||
|
||||
RFC 6125 wildcard matching was incorrectly implemented, so that a wildcard
|
||||
certificate such as ``b*.domain.com`` would match any hosts ``*b*.domain.com``
|
||||
instead of just server names beginning with ``b``. The host and certificate
|
||||
would still have to be in the same domain name. Reported by Fabian Weißberg of
|
||||
Rohde and Schwarz Cybersecurity.
|
||||
|
||||
Bug introduced in 2.2.0, fixed in 2.5.0
|
||||
|
||||
2017
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2017-10-02 (CVE-2017-14737): Potential side channel using cache information
|
||||
|
||||
In the Montgomery exponentiation code, a table of precomputed values
|
||||
is used. An attacker able to analyze which cache lines were accessed
|
||||
(perhaps via an active attack such as Prime+Probe) could recover
|
||||
information about the exponent. Identified in "CacheD: Identifying
|
||||
Cache-Based Timing Channels in Production Software" by Wang, Wang,
|
||||
Liu, Zhang, and Wu (Usenix Security 2017).
|
||||
|
||||
Fixed in 1.10.17 and 2.3.0, all prior versions affected.
|
||||
|
||||
* 2017-07-16: Failure to fully zeroize memory before free
|
||||
|
||||
The secure_allocator type attempts to zeroize memory before freeing it. Due to
|
||||
a error sometimes only a portion of the memory would be zeroed, because of a
|
||||
confusion between the number of elements vs the number of bytes that those
|
||||
elements use. So byte vectors would always be fully zeroed (since the two
|
||||
notions result in the same value), but for example with an array of 32-bit
|
||||
integers, only the first 1/4 of the elements would be zeroed before being
|
||||
deallocated. This may result in information leakage, if an attacker can access
|
||||
memory on the heap. Reported by Roman Pozlevich.
|
||||
|
||||
Bug introduced in 1.11.10, fixed in 2.2.0
|
||||
|
||||
* 2017-04-04 (CVE-2017-2801): Incorrect comparison in X.509 DN strings
|
||||
|
||||
Botan's implementation of X.509 name comparisons had a flaw which
|
||||
could result in an out of bound memory read while processing a
|
||||
specially formed DN. This could potentially be exploited for
|
||||
information disclosure or denial of service, or result in incorrect
|
||||
validation results. Found independently by Aleksandar Nikolic of
|
||||
Cisco Talos, and OSS-Fuzz automated fuzzing infrastructure.
|
||||
|
||||
Bug introduced in 1.6.0 or earlier, fixed in 2.1.0 and 1.10.16
|
||||
|
||||
* 2017-03-23 (CVE-2017-7252): Incorrect bcrypt computation
|
||||
|
||||
Botan's implementation of bcrypt password hashing scheme truncated long
|
||||
passwords at 56 characters, instead of at bcrypt's standard 72 characters
|
||||
limit. Passwords with lengths between these two bounds could be cracked more
|
||||
easily than should be the case due to the final password bytes being ignored.
|
||||
Found and reported by Solar Designer.
|
||||
|
||||
Bug introduced in 1.11.0, fixed in 2.1.0.
|
||||
|
||||
2016
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2016-11-27 (CVE-2016-9132) Integer overflow in BER decoder
|
||||
|
||||
While decoding BER length fields, an integer overflow could occur. This could
|
||||
occur while parsing untrusted inputs such as X.509 certificates. The overflow
|
||||
does not seem to lead to any obviously exploitable condition, but exploitation
|
||||
cannot be positively ruled out. Only 32-bit platforms are likely affected; to
|
||||
cause an overflow on 64-bit the parsed data would have to be many gigabytes.
|
||||
Bug found by Falko Strenzke, cryptosource GmbH.
|
||||
|
||||
Fixed in 1.10.14 and 1.11.34, all prior versions affected.
|
||||
|
||||
* 2016-10-26 (CVE-2016-8871) OAEP side channel
|
||||
|
||||
A side channel in OAEP decoding could be used to distinguish RSA ciphertexts
|
||||
that did or did not have a leading 0 byte. For an attacker capable of
|
||||
precisely measuring the time taken for OAEP decoding, this could be used as an
|
||||
oracle allowing decryption of arbitrary RSA ciphertexts. Remote exploitation
|
||||
seems difficult as OAEP decoding is always paired with RSA decryption, which
|
||||
takes substantially more (and variable) time, and so will tend to mask the
|
||||
timing channel. This attack does seems well within reach of a local attacker
|
||||
capable of a cache or branch predictor based side channel attack. Finding,
|
||||
analysis, and patch by Juraj Somorovsky.
|
||||
|
||||
Introduced in 1.11.29, fixed in 1.11.33
|
||||
|
||||
* 2016-08-30 (CVE-2016-6878) Undefined behavior in Curve25519
|
||||
|
||||
On systems without a native 128-bit integer type, the Curve25519 code invoked
|
||||
undefined behavior. This was known to produce incorrect results on 32-bit ARM
|
||||
when compiled by Clang.
|
||||
|
||||
Introduced in 1.11.12, fixed in 1.11.31
|
||||
|
||||
* 2016-08-30 (CVE-2016-6879) Bad result from X509_Certificate::allowed_usage
|
||||
|
||||
If allowed_usage was called with more than one Key_Usage set in the enum
|
||||
value, the function would return true if *any* of the allowed usages were set,
|
||||
instead of if *all* of the allowed usages are set. This could be used to
|
||||
bypass an application key usage check. Credit to Daniel Neus of Rohde &
|
||||
Schwarz Cybersecurity for finding this issue.
|
||||
|
||||
Introduced in 1.11.0, fixed in 1.11.31
|
||||
|
||||
* 2016-03-17 (CVE-2016-2849): ECDSA side channel
|
||||
|
||||
ECDSA (and DSA) signature algorithms perform a modular inverse on the
|
||||
signature nonce `k`. The modular inverse algorithm used had input dependent
|
||||
loops, and it is possible a side channel attack could recover sufficient
|
||||
information about the nonce to eventually recover the ECDSA secret key. Found
|
||||
by Sean Devlin.
|
||||
|
||||
Introduced in 1.7.15, fixed in 1.10.13 and 1.11.29
|
||||
|
||||
* 2016-03-17 (CVE-2016-2850): Failure to enforce TLS policy
|
||||
|
||||
TLS v1.2 allows negotiating which signature algorithms and hash functions each
|
||||
side is willing to accept. However received signatures were not actually
|
||||
checked against the specified policy. This had the effect of allowing a
|
||||
server to use an MD5 or SHA-1 signature, even though the default policy
|
||||
prohibits it. The same issue affected client cert authentication.
|
||||
|
||||
The TLS client also failed to verify that the ECC curve the server chose to
|
||||
use was one which was acceptable by the client policy.
|
||||
|
||||
Introduced in 1.11.0, fixed in 1.11.29
|
||||
|
||||
* 2016-02-01 (CVE-2016-2196): Overwrite in P-521 reduction
|
||||
|
||||
The P-521 reduction function would overwrite zero to one word
|
||||
following the allocated block. This could potentially result
|
||||
in remote code execution or a crash. Found with AFL
|
||||
|
||||
Introduced in 1.11.10, fixed in 1.11.27
|
||||
|
||||
* 2016-02-01 (CVE-2016-2195): Heap overflow on invalid ECC point
|
||||
|
||||
The PointGFp constructor did not check that the affine coordinate
|
||||
arguments were less than the prime, but then in curve multiplication
|
||||
assumed that both arguments if multiplied would fit into an integer
|
||||
twice the size of the prime.
|
||||
|
||||
The bigint_mul and bigint_sqr functions received the size of the
|
||||
output buffer, but only used it to dispatch to a faster algorithm in
|
||||
cases where there was sufficient output space to call an unrolled
|
||||
multiplication function.
|
||||
|
||||
The result is a heap overflow accessible via ECC point decoding,
|
||||
which accepted untrusted inputs. This is likely exploitable for
|
||||
remote code execution.
|
||||
|
||||
On systems which use the mlock pool allocator, it would allow an
|
||||
attacker to overwrite memory held in secure_vector objects. After
|
||||
this point the write will hit the guard page at the end of the
|
||||
mmap'ed region so it probably could not be used for code execution
|
||||
directly, but would allow overwriting adjacent key material.
|
||||
|
||||
Found by Alex Gaynor fuzzing with AFL
|
||||
|
||||
Introduced in 1.9.18, fixed in 1.11.27 and 1.10.11
|
||||
|
||||
* 2016-02-01 (CVE-2016-2194): Infinite loop in modular square root algorithm
|
||||
|
||||
The ressol function implements the Tonelli-Shanks algorithm for
|
||||
finding square roots could be sent into a nearly infinite loop due
|
||||
to a misplaced conditional check. This could occur if a composite
|
||||
modulus is provided, as this algorithm is only defined for primes.
|
||||
This function is exposed to attacker controlled input via the OS2ECP
|
||||
function during ECC point decompression. Found by AFL
|
||||
|
||||
Introduced in 1.7.15, fixed in 1.11.27 and 1.10.11
|
||||
|
||||
2015
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2015-11-04: TLS certificate authentication bypass
|
||||
|
||||
When the bugs affecting X.509 path validation were fixed in 1.11.22, a check
|
||||
in Credentials_Manager::verify_certificate_chain was accidentally removed
|
||||
which caused path validation failures not to be signaled to the TLS layer. So
|
||||
for affected versions, certificate authentication in TLS is bypassed. As a
|
||||
workaround, applications can override the call and implement the correct
|
||||
check. Reported by Florent Le Coz in GH #324
|
||||
|
||||
Introduced in 1.11.22, fixed in 1.11.24
|
||||
|
||||
* 2015-10-26 (CVE-2015-7824): Padding oracle attack on TLS
|
||||
|
||||
A padding oracle attack was possible against TLS CBC ciphersuites because if a
|
||||
certain length check on the packet fields failed, a different alert type than
|
||||
one used for message authentication failure would be returned to the sender.
|
||||
This check triggering would leak information about the value of the padding
|
||||
bytes and could be used to perform iterative decryption.
|
||||
|
||||
As with most such oracle attacks, the danger depends on the underlying
|
||||
protocol - HTTP servers are particularly vulnerable. The current analysis
|
||||
suggests that to exploit it an attacker would first have to guess several
|
||||
bytes of plaintext, but again this is quite possible in many situations
|
||||
including HTTP.
|
||||
|
||||
Found in a review by Sirrix AG and 3curity GmbH.
|
||||
|
||||
Introduced in 1.11.0, fixed in 1.11.22
|
||||
|
||||
* 2015-10-26 (CVE-2015-7825): Infinite loop during certificate path validation
|
||||
|
||||
When evaluating a certificate path, if a loop in the certificate chain
|
||||
was encountered (for instance where C1 certifies C2, which certifies C1)
|
||||
an infinite loop would occur eventually resulting in memory exhaustion.
|
||||
Found in a review by Sirrix AG and 3curity GmbH.
|
||||
|
||||
Introduced in 1.11.6, fixed in 1.11.22
|
||||
|
||||
* 2015-10-26 (CVE-2015-7826): Acceptance of invalid certificate names
|
||||
|
||||
RFC 6125 specifies how to match a X.509v3 certificate against a DNS name
|
||||
for application usage.
|
||||
|
||||
Otherwise valid certificates using wildcards would be accepted as matching
|
||||
certain hostnames that should they should not according to RFC 6125. For
|
||||
example a certificate issued for ``*.example.com`` should match
|
||||
``foo.example.com`` but not ``example.com`` or ``bar.foo.example.com``. Previously
|
||||
Botan would accept such a certificate as also valid for ``bar.foo.example.com``.
|
||||
|
||||
RFC 6125 also requires that when matching a X.509 certificate against a DNS
|
||||
name, the CN entry is only compared if no subjectAlternativeName entry is
|
||||
available. Previously X509_Certificate::matches_dns_name would always check
|
||||
both names.
|
||||
|
||||
Found in a review by Sirrix AG and 3curity GmbH.
|
||||
|
||||
Introduced in 1.11.0, fixed in 1.11.22
|
||||
|
||||
* 2015-10-26 (CVE-2015-7827): PKCS #1 v1.5 decoding was not constant time
|
||||
|
||||
During RSA decryption, how long decoding of PKCS #1 v1.5 padding took was
|
||||
input dependent. If these differences could be measured by an attacker, it
|
||||
could be used to mount a Bleichenbacher million-message attack. PKCS #1 v1.5
|
||||
decoding has been rewritten to use a sequence of operations which do not
|
||||
contain any input-dependent indexes or jumps. Notations for checking constant
|
||||
time blocks with ctgrind (https://github.com/agl/ctgrind) were added to PKCS
|
||||
#1 decoding among other areas. Found in a review by Sirrix AG and 3curity GmbH.
|
||||
|
||||
Fixed in 1.11.22 and 1.10.13. Affected all previous versions.
|
||||
|
||||
* 2015-08-03 (CVE-2015-5726): Crash in BER decoder
|
||||
|
||||
The BER decoder would crash due to reading from offset 0 of an empty vector if
|
||||
it encountered a BIT STRING which did not contain any data at all. This can be
|
||||
used to easily crash applications reading untrusted ASN.1 data, but does not
|
||||
seem exploitable for code execution. Found with afl.
|
||||
|
||||
Fixed in 1.11.19 and 1.10.10, affected all previous versions of 1.10 and 1.11
|
||||
|
||||
* 2015-08-03 (CVE-2015-5727): Excess memory allocation in BER decoder
|
||||
|
||||
The BER decoder would allocate a fairly arbitrary amount of memory in a length
|
||||
field, even if there was no chance the read request would succeed. This might
|
||||
cause the process to run out of memory or invoke the OOM killer. Found with afl.
|
||||
|
||||
Fixed in 1.11.19 and 1.10.10, affected all previous versions of 1.10 and 1.11
|
||||
|
||||
2014
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 2014-04-10 (CVE-2014-9742): Insufficient randomness in Miller-Rabin primality check
|
||||
|
||||
A bug in the Miller-Rabin primality test resulted in only a single random base
|
||||
being used instead of a sequence of such bases. This increased the probability
|
||||
that a non-prime would be accepted by is_prime or that a randomly generated
|
||||
prime might actually be composite. The probability of a random 1024 bit
|
||||
number being incorrectly classed as prime with a single base is around 2^-40.
|
||||
Reported by Jeff Marrison.
|
||||
|
||||
Introduced in 1.8.3, fixed in 1.10.8 and 1.11.9
|
@ -1,32 +0,0 @@
|
||||
Semantic Versioning
|
||||
=====================
|
||||
|
||||
Starting with 2.0.0, Botan adopted semantic versioning. This means we endevour
|
||||
to make no change which will either break compilation of existing code, or cause
|
||||
different behavior in a way that will cause compatability issues. Such changes
|
||||
are reserved for new major versions.
|
||||
|
||||
If on upgrading to a new minor version, you encounter a problem where your
|
||||
existing code either fails to compile, or the code behaves differently in some
|
||||
way that causes trouble, it is probably a bug; please report it on Github.
|
||||
|
||||
Exception
|
||||
-----------------------
|
||||
|
||||
There is an important exception to the SemVer guarantees that you should be
|
||||
aware of. If you in your application derive a new class from a class in the
|
||||
library, we do not guarantee a future minor release will not break your
|
||||
code. For example, we may in a minor release introduce a new pure virtual
|
||||
function to a base class like ``BlockCipher``, and implement it for all
|
||||
subclasses within the library. In this case your code would fail to compile
|
||||
until you implemented the new virtual function. Or we might rename or remove a
|
||||
protected function, or a protected member variable.
|
||||
|
||||
There is also an exception to this exception! The following classes are intended
|
||||
for derivation by applications, and are fully covered by SemVer:
|
||||
|
||||
* ``Credentials_Manager``
|
||||
* ``Entropy_Source``
|
||||
* ``TLS::Callbacks``
|
||||
* ``TLS::Policy`` (and subclasses thereof)
|
||||
* ``TLS::Stream<T>``
|
@ -1,469 +0,0 @@
|
||||
Side Channels
|
||||
=========================
|
||||
|
||||
Many cryptographic systems can be easily broken by side channels. This document
|
||||
notes side channel protections which are currently implemented, as well as areas
|
||||
of the code which are known to be vulnerable to side channels. The latter are
|
||||
obviously all open for future improvement.
|
||||
|
||||
The following text assumes the reader is already familiar with cryptographic
|
||||
implementations, side channel attacks, and common countermeasures.
|
||||
|
||||
Modular Exponentiation
|
||||
------------------------
|
||||
|
||||
Modular exponentiation uses a fixed window algorithm with Montgomery
|
||||
representation. A side channel silent table lookup is used to access the
|
||||
precomputed powers. The caller provides the maximum possible bit length of the
|
||||
exponent, and the exponent is zero-padded as required. For example, in a DSA
|
||||
signature with 256-bit q, the caller will specify a maximum length of exponent
|
||||
of 256 bits, even if the k that was generated was 250 bits. This avoids leaking
|
||||
the length of the exponent through the number of loop iterations.
|
||||
See monty_exp.cpp and monty.cpp
|
||||
|
||||
Karatsuba multiplication algorithm avoids any conditional branches; in
|
||||
cases where different operations must be performed it instead uses masked
|
||||
operations. See mp_karat.cpp for details.
|
||||
|
||||
The Montgomery reduction is written to run in constant time.
|
||||
The final reduction is handled with a masked subtraction. See mp_monty.cpp.
|
||||
|
||||
Barrett Reduction
|
||||
--------------------
|
||||
|
||||
The Barrett reduction code is written to avoid input dependent branches. The
|
||||
Barrett algorithm only works for inputs up to a certain size, and larger values
|
||||
fall back on a different (slower) division algorithm. This secondary algorithm
|
||||
is also const time, but the branch allows detecting when a value larger than
|
||||
2^{2k} was reduced, where k is the word length of the modulus. This leaks only
|
||||
the size of the two values, and not anything else about their value.
|
||||
|
||||
RSA
|
||||
----------------------
|
||||
|
||||
Blinding is always used to protect private key operations (there is no way to
|
||||
turn it off). Both base blinding and exponent blinding are used.
|
||||
|
||||
For base blinding, as an optimization, instead of choosing a new random mask and
|
||||
inverse with each decryption, both the mask and its inverse are simply squared
|
||||
to choose the next blinding factor. This is much faster than computing a fresh
|
||||
value each time, and the additional relation is thought to provide only minimal
|
||||
useful information for an attacker. Every BOTAN_BLINDING_REINIT_INTERVAL
|
||||
(default 64) operations, a new starting point is chosen.
|
||||
|
||||
Exponent blinding uses new values for each signature, with 64 bit masks.
|
||||
|
||||
RSA signing uses the CRT optimization, which is much faster but vulnerable to
|
||||
trivial fault attacks [RsaFault] which can result in the key being entirely
|
||||
compromised. To protect against this (or any other computational error which
|
||||
would have the same effect as a fault attack in this case), after every private
|
||||
key operation the result is checked for consistency with the public key. This
|
||||
introduces only slight additional overhead and blocks most fault attacks; it is
|
||||
possible to use a second fault attack to bypass this verification, but such a
|
||||
double fault attack requires significantly more control on the part of an
|
||||
attacker than a BellCore style attack, which is possible if any error at all
|
||||
occurs during either modular exponentiation involved in the RSA signature
|
||||
operation.
|
||||
|
||||
RSA key generation is also prone to side channel vulnerabilities due to the need
|
||||
to calculate the CRT parameters. The GCD computation, LCM computations, modulo,
|
||||
and inversion of ``q`` modulo ``p`` are all done via constant time algorithms.
|
||||
An additional inversion, of ``e`` modulo ``phi(n)``, is also required. This one
|
||||
is somewhat more complicated because ``phi(n)`` is even and the primary constant
|
||||
time algorithm for inversions only works for odd moduli. This is worked around
|
||||
by a technique based on the CRT - ``phi(n)`` is factored to ``2**e * z`` for
|
||||
some ``e`` > 1 and some odd ``z``. Then ``e`` is inverted modulo ``2**e`` and
|
||||
also modulo ``z``. The inversion modulo ``2**e`` is done via a specialized
|
||||
constant-time algoirthm which only works for powers of 2. Then the two
|
||||
inversions are combined using the CRT. This process does leak the value of
|
||||
``e``; to avoid problems ``p`` and ``q`` are chosen so that ``e`` is always 1.
|
||||
|
||||
See blinding.cpp and rsa.cpp.
|
||||
|
||||
Decryption of PKCS #1 v1.5 Ciphertexts
|
||||
----------------------------------------
|
||||
|
||||
This padding scheme is used with RSA, and is very vulnerable to errors. In a
|
||||
scenario where an attacker can repeatedly present RSA ciphertexts, and a
|
||||
legitimate key holder will attempt to decrypt each ciphertext and simply
|
||||
indicates to the attacker if the PKCS padding was valid or not (without
|
||||
revealing any additional information), the attacker can use this behavior as an
|
||||
oracle to perform iterative decryption of arbitrary RSA ciphertexts encrypted
|
||||
under that key. This is the famous million message attack [MillionMsg]. A side
|
||||
channel such as a difference in time taken to handle valid and invalid RSA
|
||||
ciphertexts is enough to mount the attack [MillionMsgTiming].
|
||||
|
||||
As a first step, the PKCS v1.5 decoding operation runs without any
|
||||
conditional jumps or indexes, with the only variance in runtime being
|
||||
based on the length of the public modulus, which is public information.
|
||||
|
||||
Preventing the attack in full requires some application level changes. In
|
||||
protocols which know the expected length of the encrypted key, PK_Decryptor
|
||||
provides the function `decrypt_or_random` which first generates a random fake
|
||||
key, then decrypts the presented ciphertext, then in constant time either copies
|
||||
out the random key or the decrypted plaintext depending on if the ciphertext was
|
||||
valid or not (valid padding and expected plaintext length). Then in the case of
|
||||
an attack, the protocol will carry on with a randomly chosen key, which will
|
||||
presumably cause total failure in a way that does not allow an attacker to
|
||||
distinguish (via any timing or other side channel, nor any error messages
|
||||
specific to the one situation vs the other) if the RSA padding was valid or
|
||||
invalid.
|
||||
|
||||
One very important user of PKCS #1 v1.5 encryption is the TLS protocol. In TLS,
|
||||
some extra versioning information is embedded in the plaintext message, along
|
||||
with the key. It turns out that this version information must be treated in an
|
||||
identical (constant-time) way with the PKCS padding, or again the system is
|
||||
broken. [VersionOracle]. This is supported by a special version of
|
||||
PK_Decryptor::decrypt_or_random that additionally allows verifying one or more
|
||||
content bytes, in addition to the PKCS padding.
|
||||
|
||||
See eme_pkcs.cpp and pubkey.cpp.
|
||||
|
||||
Verification of PKCS #1 v1.5 Signatures
|
||||
----------------------------------------
|
||||
|
||||
One way of verifying PKCS #1 v1.5 signature padding is to decode it with an
|
||||
ASN.1 BER parser. However such a design commonly leads to accepting signatures
|
||||
besides the (single) valid RSA PKCS #1 v1.5 signature for any given message,
|
||||
because often the BER parser accepts variations of the encoding which are
|
||||
actually invalid. It also needlessly exposes the BER parser to untrusted inputs.
|
||||
|
||||
It is safer and simpler to instead re-encode the hash value we are expecting
|
||||
using the PKCS #1 v1.5 encoding rules, and const time compare our expected
|
||||
encoding with the output of the RSA operation. So that is what Botan does.
|
||||
|
||||
See emsa_pkcs.cpp.
|
||||
|
||||
OAEP
|
||||
----------------------
|
||||
|
||||
RSA OAEP is (PKCS#1 v2) is the recommended version of RSA encoding standard,
|
||||
because it is not directly vulnerable to Bleichenbacher attack. However, if
|
||||
implemented incorrectly, a side channel can be presented to an attacker and
|
||||
create an oracle for decrypting RSA ciphertexts [OaepTiming].
|
||||
|
||||
This attack is avoided in Botan by making the OAEP decoding operation run
|
||||
without any conditional jumps or indexes, with the only variance in runtime
|
||||
coming from the length of the RSA key (which is public information).
|
||||
|
||||
See eme_oaep.cpp.
|
||||
|
||||
ECC point decoding
|
||||
----------------------
|
||||
|
||||
The API function OS2ECP, which is used to convert byte strings to ECC points,
|
||||
verifies that all points satisfy the ECC curve equation. Points that do not
|
||||
satisfy the equation are invalid, and can sometimes be used to break
|
||||
protocols ([InvalidCurve] [InvalidCurveTLS]). See ec_point.cpp.
|
||||
|
||||
ECC scalar multiply
|
||||
----------------------
|
||||
|
||||
There are several different implementations of ECC scalar multiplications which
|
||||
depend on the API invoked. This include ``EC_Point::operator*``,
|
||||
``EC_Group::blinded_base_point_multiply`` and
|
||||
``EC_Group::blinded_var_point_multiply``.
|
||||
|
||||
The ``EC_Point::operator*`` implementation uses the Montgomery ladder, which is
|
||||
fairly resistant to side channels. However it leaks the size of the scalar,
|
||||
because the loop iterations are bounded by the scalar size. It should not be
|
||||
used in cases when the scalar is a secret.
|
||||
|
||||
Both ``blinded_base_point_multiply`` and ``blinded_var_point_multiply`` apply
|
||||
side channel countermeasures. The scalar is masked by a multiple of the group
|
||||
order (this is commonly called Coron's first countermeasure [CoronDpa]),
|
||||
currently the mask is scaled to be half the bit length of the order of the group.
|
||||
|
||||
Botan stores all ECC points in Jacobian representation. This form allows faster
|
||||
computation by representing points (x,y) as (X,Y,Z) where x=X/Z^2 and
|
||||
y=Y/Z^3. As the representation is redundant, for any randomly chosen non-zero r,
|
||||
(X*r^2,Y*r^3,Z*r) is an equivalent point. Changing the point values prevents an
|
||||
attacker from mounting attacks based on the input point remaining unchanged over
|
||||
multiple executions. This is commonly called Coron's third countermeasure, see
|
||||
again [CoronDpa].
|
||||
|
||||
The base point multiplication algorithm is a comb-like technique which
|
||||
precomputes ``P^i,(2*P)^i,(3*P)^i`` for all ``i`` in the range of valid scalars.
|
||||
This means the scalar multiplication involves only point additions and no
|
||||
doublings, which may help against attacks which rely on distinguishing between
|
||||
point doublings and point additions. The elements of the table are accessed by
|
||||
masked lookups, so as not to leak information about bits of the scalar via a
|
||||
cache side channel. However, whenever 3 sequential bits of the (masked) scalar
|
||||
are all 0, no operation is performed in that iteration of the loop. This exposes
|
||||
the scalar multiply to a cache-based side channel attack; scalar blinding is
|
||||
necessary to prevent this attack from leaking information about the scalar.
|
||||
|
||||
The variable point multiplication algorithm uses a fixed-window algorithm. Since
|
||||
this is normally invoked using untrusted points (eg during ECDH key exchange) it
|
||||
randomizes all inputs to prevent attacks which are based on chosen input
|
||||
points. The table of precomputed multiples is accessed using a masked lookup
|
||||
which should not leak information about the secret scalar to an attacker who can
|
||||
mount a cache-based side channel attack.
|
||||
|
||||
See ec_point.cpp and point_mul.cpp in src/lib/pubkey/ec_group
|
||||
|
||||
ECDH
|
||||
----------------------
|
||||
|
||||
ECDH verifies (through its use of OS2ECP) that all input points received from
|
||||
the other party satisfy the curve equation. This prevents twist attacks. The
|
||||
same check is performed on the output point, which helps prevent fault attacks.
|
||||
|
||||
ECDSA
|
||||
----------------------
|
||||
|
||||
Inversion of the ECDSA nonce k must be done in constant time, as any leak of
|
||||
even a single bit of the nonce can be sufficient to allow recovering the private
|
||||
key. In Botan all inverses modulo an odd number are performed using a constant
|
||||
time algorithm due to Niels Möller.
|
||||
|
||||
x25519
|
||||
----------------------
|
||||
|
||||
The x25519 code is independent of the main Weierstrass form ECC code, instead
|
||||
based on curve25519-donna-c64.c by Adam Langley. The code seems immune to cache
|
||||
based side channels. It does make use of integer multiplications; on some old
|
||||
CPUs these multiplications take variable time and might allow a side channel
|
||||
attack. This is not considered a problem on modern processors.
|
||||
|
||||
TLS CBC ciphersuites
|
||||
----------------------
|
||||
|
||||
The original TLS v1.0 CBC Mac-then-Encrypt mode is vulnerable to an oracle
|
||||
attack. If an attacker can distinguish padding errors through different error
|
||||
messages [TlsCbcOracle] or via a side channel attack like [Lucky13], they can
|
||||
abuse the server as a decryption oracle.
|
||||
|
||||
The side channel protection for Lucky13 follows the approach proposed in the
|
||||
Lucky13 paper. It is not perfectly constant time, but does hide the padding
|
||||
oracle in practice. Tools to test TLS CBC decoding are included in the timing
|
||||
tests. See https://github.com/randombit/botan/pull/675 for more information.
|
||||
|
||||
The Encrypt-then-MAC extension, which completely avoids the side channel, is
|
||||
implemented and used by default for CBC ciphersuites.
|
||||
|
||||
CBC mode padding
|
||||
----------------------
|
||||
|
||||
In theory, any good protocol protects CBC ciphertexts with a MAC. But in
|
||||
practice, some protocols are not good and cannot be fixed immediately. To avoid
|
||||
making a bad problem worse, the code to handle decoding CBC ciphertext padding
|
||||
bytes runs in constant time, depending only on the block size of the cipher.
|
||||
|
||||
base64 decoding
|
||||
----------------------
|
||||
|
||||
Base64 (and related encodings base32, base58 and hex) are sometimes used to
|
||||
encode or decode secret data. To avoid possible side channels which might leak
|
||||
key material during the encoding or decoding process, these functions avoid any
|
||||
input-dependent table lookups.
|
||||
|
||||
AES
|
||||
----------------------
|
||||
|
||||
Some x86, ARMv8 and POWER processors support AES instructions which
|
||||
are fast and are thought to be side channel silent. These instructions
|
||||
are used when available.
|
||||
|
||||
On CPUs which do not have hardware AES instructions but do support SIMD vectors
|
||||
with a byte shuffle (including x86's SSSE3, ARM's NEON and PowerPC AltiVec), a
|
||||
version of AES is implemented which is side channel silent. This implementation
|
||||
is based on code by Mike Hamburg [VectorAes], see aes_vperm.cpp.
|
||||
|
||||
On all other processors, a constant time bitsliced implementation is used. This
|
||||
is typically slower than the vector permute implementation, and additionally for
|
||||
best performance multiple blocks must be processed in parellel. So modes such
|
||||
as CTR, GCM or XTS are relatively fast, but others such as CBC encryption
|
||||
suffer.
|
||||
|
||||
GCM
|
||||
---------------------
|
||||
|
||||
On platforms that support a carryless multiply instruction (ARMv8 and recent x86),
|
||||
GCM is fast and constant time.
|
||||
|
||||
On all other platforms, GCM uses an algorithm based on precomputing all powers
|
||||
of H from 1 to 128. Then for every bit of the input a mask is formed which
|
||||
allows conditionally adding that power without leaking information via a cache
|
||||
side channel. There is also an SSSE3 variant of this algorithm which is somewhat
|
||||
faster on processors which have SSSE3 but no AES-NI instructions.
|
||||
|
||||
OCB
|
||||
-----------------------
|
||||
|
||||
It is straightforward to implement OCB mode in a efficient way that does not
|
||||
depend on any secret branches or lookups. See ocb.cpp for the implementation.
|
||||
|
||||
Poly1305
|
||||
----------------------
|
||||
|
||||
The Poly1305 implementation does not have any secret lookups or conditionals.
|
||||
The code is based on the public domain version by Andrew Moon.
|
||||
|
||||
DES/3DES
|
||||
----------------------
|
||||
|
||||
The DES implementation relies on table lookups but they are limited to
|
||||
tables which are exactly 64 bytes in size. On systems with 64 byte (or
|
||||
larger) cache lines, these should not leak information. It may still
|
||||
be vulnerable to side channels on processors which leak cache line
|
||||
access offsets via cache bank conflicts; vulnerable hardware includes
|
||||
Sandy Bridge processors, but not later Intel or AMD CPUs.
|
||||
|
||||
Twofish
|
||||
------------------------
|
||||
|
||||
This algorithm uses table lookups with secret sboxes. No cache-based side
|
||||
channel attack on Twofish has ever been published, but it is possible nobody
|
||||
sufficiently skilled has ever tried.
|
||||
|
||||
ChaCha20, Serpent, Threefish, ...
|
||||
-----------------------------------
|
||||
|
||||
Some algorithms including ChaCha, Salsa, Serpent and Threefish are 'naturally'
|
||||
silent to cache and timing side channels on all recent processors.
|
||||
|
||||
IDEA
|
||||
---------------
|
||||
|
||||
IDEA encryption, decryption, and key schedule are implemented to take constant
|
||||
time regardless of their inputs.
|
||||
|
||||
Hash Functions
|
||||
-------------------------
|
||||
|
||||
Most hash functions included in Botan such as MD5, SHA-1, SHA-2, SHA-3, Skein,
|
||||
and BLAKE2 do not require any input-dependent memory lookups, and so seem to not be
|
||||
affected by common CPU side channels. However the implementations of Whirlpool
|
||||
and Streebog use table lookups and probably can be attacked by side channels.
|
||||
|
||||
Memory comparisons
|
||||
----------------------
|
||||
|
||||
The function same_mem in header mem_ops.h provides a constant-time comparison
|
||||
function. It is used when comparing MACs or other secret values. It is also
|
||||
exposed for application use.
|
||||
|
||||
Memory zeroizing
|
||||
----------------------
|
||||
|
||||
There is no way in portable C/C++ to zero out an array before freeing it, in
|
||||
such a way that it is guaranteed that the compiler will not elide the
|
||||
'additional' (seemingly unnecessary) writes to zero out the memory.
|
||||
|
||||
The function secure_scrub_memory (in mem_ops.cpp) uses some system specific
|
||||
trick to zero out an array. If possible an OS provided routine (such as
|
||||
``RtlSecureZeroMemory`` or ``explicit_bzero``) is used.
|
||||
|
||||
On other platforms, by default the trick of referencing memset through a
|
||||
volatile function pointer is used. This approach is not guaranteed to work on
|
||||
all platforms, and currently there is no systematic check of the resulting
|
||||
binary function that it is compiled as expected. But, it is the best approach
|
||||
currently known and has been verified to work as expected on common platforms.
|
||||
|
||||
If BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO is set to 0 in build.h (not the default) a
|
||||
byte at a time loop through a volatile pointer is used to overwrite the array.
|
||||
|
||||
Memory allocation
|
||||
----------------------
|
||||
|
||||
Botan's secure_vector type is a std::vector with a custom allocator. The
|
||||
allocator calls secure_scrub_memory before freeing memory.
|
||||
|
||||
Some operating systems support an API call to lock a range of pages
|
||||
into memory, such that they will never be swapped out (``mlock`` on POSIX,
|
||||
``VirtualLock`` on Windows). On many POSIX systems ``mlock`` is only usable by
|
||||
root, but on Linux, FreeBSD and possibly other systems a small amount
|
||||
of memory can be locked by processes without extra credentials.
|
||||
|
||||
If available, Botan uses such a region for storing key material. A page-aligned
|
||||
block of memory is allocated and locked, then the memory is scrubbed before
|
||||
freeing. This memory pool is used by secure_vector when available. It can be
|
||||
disabled at runtime setting the environment variable BOTAN_MLOCK_POOL_SIZE to 0.
|
||||
|
||||
Automated Analysis
|
||||
---------------------
|
||||
|
||||
Currently the main tool used by the Botan developers for testing for side
|
||||
channels at runtime is valgrind; valgrind's runtime API is used to taint memory
|
||||
values, and any jumps or indexes using data derived from these values will cause
|
||||
a valgrind warning. This technique was first used by Adam Langley in ctgrind.
|
||||
See header ct_utils.h.
|
||||
|
||||
To check, install valgrind, configure the build with --with-valgrind, and run
|
||||
the tests.
|
||||
|
||||
.. highlight:: shell
|
||||
|
||||
There is also a test utility built into the command line util, `timing_test`,
|
||||
which runs an operation on several different inputs many times in order to
|
||||
detect simple timing differences. The output can be processed using the
|
||||
Mona timing report library (https://github.com/seecurity/mona-timing-report).
|
||||
To run a timing report (here for example pow_mod)::
|
||||
|
||||
$ ./botan timing_test pow_mod > pow_mod.raw
|
||||
|
||||
This must be run from a checkout of the source, or otherwise ``--test-data-dir=``
|
||||
must be used to point to the expected input files.
|
||||
|
||||
Build and run the Mona report as::
|
||||
|
||||
$ git clone https://github.com/seecurity/mona-timing-report.git
|
||||
$ cd mona-timing-report
|
||||
$ ant
|
||||
$ java -jar ReportingTool.jar --lowerBound=0.4 --upperBound=0.5 --inputFile=pow_mod.raw --name=PowMod
|
||||
|
||||
This will produce plots and an HTML file in subdirectory starting with
|
||||
``reports_`` followed by a representation of the current date and time.
|
||||
|
||||
References
|
||||
---------------
|
||||
|
||||
[Aes256Sc] Neve, Tiri "On the complexity of side-channel attacks on AES-256"
|
||||
(https://eprint.iacr.org/2007/318.pdf)
|
||||
|
||||
[AesCacheColl] Bonneau, Mironov "Cache-Collision Timing Attacks Against AES"
|
||||
(http://www.jbonneau.com/doc/BM06-CHES-aes_cache_timing.pdf)
|
||||
|
||||
[CoronDpa] Coron,
|
||||
"Resistance against Differential Power Analysis for Elliptic Curve Cryptosystems"
|
||||
(https://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.1.5695)
|
||||
|
||||
[InvalidCurve] Biehl, Meyer, Müller: Differential fault attacks on
|
||||
elliptic curve cryptosystems
|
||||
(https://www.iacr.org/archive/crypto2000/18800131/18800131.pdf)
|
||||
|
||||
[InvalidCurveTLS] Jager, Schwenk, Somorovsky: Practical Invalid Curve
|
||||
Attacks on TLS-ECDH
|
||||
(https://www.nds.rub.de/research/publications/ESORICS15/)
|
||||
|
||||
[SafeCurves] Bernstein, Lange: SafeCurves: choosing safe curves for
|
||||
elliptic-curve cryptography. (https://safecurves.cr.yp.to)
|
||||
|
||||
[Lucky13] AlFardan, Paterson "Lucky Thirteen: Breaking the TLS and DTLS Record Protocols"
|
||||
(http://www.isg.rhul.ac.uk/tls/TLStiming.pdf)
|
||||
|
||||
[MillionMsg] Bleichenbacher "Chosen Ciphertext Attacks Against Protocols Based
|
||||
on the RSA Encryption Standard PKCS1"
|
||||
(https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.8543)
|
||||
|
||||
[MillionMsgTiming] Meyer, Somorovsky, Weiss, Schwenk, Schinzel, Tews: Revisiting
|
||||
SSL/TLS Implementations: New Bleichenbacher Side Channels and Attacks
|
||||
(https://www.nds.rub.de/research/publications/mswsst2014-bleichenbacher-usenix14/)
|
||||
|
||||
[OaepTiming] Manger, "A Chosen Ciphertext Attack on RSA Optimal Asymmetric
|
||||
Encryption Padding (OAEP) as Standardized in PKCS #1 v2.0"
|
||||
(http://archiv.infsec.ethz.ch/education/fs08/secsem/Manger01.pdf)
|
||||
|
||||
[RsaFault] Boneh, Demillo, Lipton
|
||||
"On the importance of checking cryptographic protocols for faults"
|
||||
(https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.9764)
|
||||
|
||||
[RandomMonty] Le, Tan, Tunstall "Randomizing the Montgomery Powering Ladder"
|
||||
(https://eprint.iacr.org/2015/657)
|
||||
|
||||
[VectorAes] Hamburg, "Accelerating AES with Vector Permute Instructions"
|
||||
https://shiftleft.org/papers/vector_aes/vector_aes.pdf
|
||||
|
||||
[VersionOracle] Klíma, Pokorný, Rosa "Attacking RSA-based Sessions in SSL/TLS"
|
||||
(https://eprint.iacr.org/2003/052)
|
@ -1,89 +0,0 @@
|
||||
Support Information
|
||||
=======================
|
||||
|
||||
Supported Platforms
|
||||
------------------------
|
||||
|
||||
For Botan 3, the tier-1 supported platforms are
|
||||
|
||||
* Linux x86-64, GCC 11.2 or later
|
||||
* Linux x86-64, Clang 14 or later
|
||||
* Linux aarch64, GCC 11.2 or later
|
||||
* Linux ppc64le, GCC 11.2 or later
|
||||
* Windows x86-64, Visual C++ 2022 or later
|
||||
|
||||
These platforms are all tested by continuous integration, and the developers
|
||||
have access to hardware in order to test patches. Problems affecting these
|
||||
platforms are considered release blockers.
|
||||
|
||||
For Botan 3, the tier-2 supported platforms are
|
||||
|
||||
* macOS x86-64, latest XCode Clang
|
||||
* iOS aarch64, latest XCode Clang
|
||||
* Windows x86-64, latest MinGW GCC
|
||||
* Android aarch64, latest NDK Clang
|
||||
* Linux arm32, GCC 11.2 or later
|
||||
* Linux x86-32, GCC 11.2 or later
|
||||
* FreeBSD x86-64, Clang 14 or later
|
||||
|
||||
.. note::
|
||||
|
||||
Notice that the minimum version requirements for XCode and NDK is different
|
||||
from other compilers. With GCC or Clang, we fix the minimum required compiler
|
||||
version and aim to maintain that support for the entire lifecycle of
|
||||
Botan 3. In contrast, for XCode and NDK the minimum version is floating;
|
||||
namely, we will only support the very latest version. It's possible earlier
|
||||
versions will work, but this is not guaranteed.
|
||||
|
||||
.. note::
|
||||
|
||||
As of June 2023, it is known that at least XCode 13.3 is required, since
|
||||
earlier versions did not support certain C++20 language features that the
|
||||
library uses. XCode 15.0 or higher is recommended.
|
||||
|
||||
.. note::
|
||||
|
||||
For Android, NDK 26 is required
|
||||
|
||||
Some (but not all) of the tier-2 platforms are tested by CI. Everything should
|
||||
work, and if problems are encountered, the developers will probably be able to
|
||||
help. But they are not as carefully tested as tier-1.
|
||||
|
||||
Of course most other modern OSes such as QNX, AIX, OpenBSD, NetBSD, and Solaris
|
||||
also work just fine. Some are tested occasionally, usually just before a new
|
||||
release. But very little code specific to these platforms is written by the
|
||||
primary developers. For example, any functionality in the library which
|
||||
utilizes OpenBSD specific APIs was likely contributed by someone interested in
|
||||
that platform.
|
||||
|
||||
In theory any working C++20 compiler is fine but in practice, we only regularly
|
||||
test with GCC, Clang, and Visual C++. Several other compilers (such as IBM XLC,
|
||||
Intel C++, and Sun Studio) are supported by the build system but are not tested
|
||||
by the developers and may have build or codegen problems. Patches to improve
|
||||
support for these compilers is welcome.
|
||||
|
||||
Branch Support Status
|
||||
-------------------------
|
||||
|
||||
Following table provides the support status for Botan branches, as of
|
||||
July 2023.
|
||||
|
||||
"Active development" refers to adding new features and optimizations. At the
|
||||
conclusion of the active development phase, only bugfixes are applied.
|
||||
|
||||
End of life dates may be extended as circumstances warrant.
|
||||
|
||||
============== ============== ========================== ============
|
||||
Branch First Release End of Active Development End of Life
|
||||
============== ============== ========================== ============
|
||||
Botan 1.8 2008-12-08 2010-08-31 2016-02-13
|
||||
Botan 1.10 2011-06-20 2012-07-10 2018-12-31
|
||||
Botan 2 2017-01-06 2020-11-05 2024-12-31 or later
|
||||
Botan 3 2023-04-11 ? 2026-12-31 or later
|
||||
============== ============== ========================== ============
|
||||
|
||||
Getting Help
|
||||
------------------
|
||||
|
||||
To get help with Botan, open an issue on
|
||||
`GitHub <https://github.com/randombit/botan/issues>`_
|
@ -1,24 +0,0 @@
|
||||
Copyright (C) 1999-2023 The Botan Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions, and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
File diff suppressed because it is too large
Load Diff
@ -1,136 +0,0 @@
|
||||
Botan: Crypto and TLS for Modern C++
|
||||
========================================
|
||||
|
||||
Botan (Japanese for peony flower) is a C++ cryptography library released under the
|
||||
permissive `Simplified BSD <https://botan.randombit.net/license.txt>`_ license.
|
||||
|
||||
Botan's goal is to be the best option for cryptography in C++ by offering the
|
||||
tools necessary to implement a range of practical systems, such as TLS protocol,
|
||||
X.509 certificates, modern AEAD ciphers, PKCS#11 and TPM hardware support,
|
||||
password hashing, and post quantum crypto schemes. A Python binding is included,
|
||||
and several other `language bindings
|
||||
<https://github.com/randombit/botan/wiki/Language-Bindings>`_ are available.
|
||||
The library is accompanied by a featureful
|
||||
`command line interface <https://botan.randombit.net/handbook/cli.html>`_.
|
||||
|
||||
See the `documentation <https://botan.randombit.net/handbook>`_ for more
|
||||
information about included features.
|
||||
|
||||
Development is coordinated on `GitHub <https://github.com/randombit/botan>`_
|
||||
and contributions are welcome. If you need help, please open an issue on
|
||||
`GitHub <https://github.com/randombit/botan/issues>`_.
|
||||
|
||||
If you think you have found a security issue, see the `security page
|
||||
<https://botan.randombit.net/security.html>`_ for contact information.
|
||||
|
||||
.. image:: https://github.com/randombit/botan/actions/workflows/ci.yml/badge.svg?branch=master
|
||||
:target: https://github.com/randombit/botan/actions/workflows/ci.yml
|
||||
:alt: CI status
|
||||
|
||||
.. image:: https://github.com/randombit/botan/actions/workflows/nightly.yml/badge.svg?branch=master
|
||||
:target: https://github.com/randombit/botan/actions/workflows/nightly.yml
|
||||
:alt: nightly CI status
|
||||
|
||||
.. image:: https://img.shields.io/coverallsCoverage/github/randombit/botan?branch=master
|
||||
:target: https://coveralls.io/github/randombit/botan
|
||||
:alt: Coverage report
|
||||
|
||||
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/botan.svg
|
||||
:target: https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_botan/latest
|
||||
:alt: OSS-Fuzz status
|
||||
|
||||
.. image:: https://repology.org/badge/tiny-repos/botan.svg
|
||||
:target: https://repology.org/project/botan/versions
|
||||
:alt: Packaging status
|
||||
|
||||
.. image:: https://api.securityscorecards.dev/projects/github.com/randombit/botan/badge
|
||||
:target: https://securityscorecards.dev/viewer/?uri=github.com/randombit/botan
|
||||
:alt: CII Best Practices statement
|
||||
|
||||
.. image:: https://bestpractices.coreinfrastructure.org/projects/531/badge
|
||||
:target: https://bestpractices.coreinfrastructure.org/projects/531
|
||||
:alt: CII Best Practices statement
|
||||
|
||||
Releases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The latest release from the Botan2 release series is
|
||||
`2.19.3 <https://botan.randombit.net/releases/Botan-2.19.3.tar.xz>`_
|
||||
`(sig) <https://botan.randombit.net/releases/Botan-2.19.3.tar.xz.asc>`_,
|
||||
released on 2022-11-16.
|
||||
|
||||
The latest release from the Botan3 release series is
|
||||
`3.2.0 <https://botan.randombit.net/releases/Botan-3.2.0.tar.xz>`_
|
||||
`(sig) <https://botan.randombit.net/releases/Botan-3.2.0.tar.xz.asc>`_,
|
||||
released on 2023-10-09.
|
||||
|
||||
All releases are signed with a `PGP key <https://botan.randombit.net/pgpkey.txt>`_.
|
||||
See the `release notes <https://botan.randombit.net/news.html>`_ for
|
||||
what is new. Botan is also available through most
|
||||
`distributions <https://github.com/randombit/botan/wiki/Distros>`_
|
||||
such as Fedora, Debian, Arch and Homebrew.
|
||||
|
||||
Find Enclosed
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Transport Layer Security (TLS) Protocol
|
||||
----------------------------------------
|
||||
|
||||
* TLS v1.2/v1.3, and DTLS v1.2
|
||||
* Supported extensions include session tickets, SNI, ALPN, OCSP stapling,
|
||||
encrypt-then-mac CBC, and extended master secret.
|
||||
* Supports authentication using certificates or preshared keys (PSK)
|
||||
* Supports record encryption with ChaCha20Poly1305, AES/OCB, AES/GCM, AES/CCM,
|
||||
Camellia/GCM as well as legacy CBC ciphersuites.
|
||||
* Key exchange using ECDH, FFDHE, or RSA
|
||||
|
||||
Public Key Infrastructure
|
||||
----------------------------------------
|
||||
|
||||
* X.509v3 certificates and CRL creation and handling
|
||||
* PKIX certificate path validation, including name constraints.
|
||||
* OCSP request creation and response handling
|
||||
* PKCS #10 certificate request generation and processing
|
||||
* Access to Windows, macOS and Unix system certificate stores
|
||||
* SQL database backed certificate store
|
||||
|
||||
Public Key Cryptography
|
||||
----------------------------------------
|
||||
|
||||
* RSA signatures and encryption
|
||||
* DH and ECDH key agreement
|
||||
* Signature schemes ECDSA, DSA, Ed25519, ECGDSA, ECKCDSA, SM2, GOST 34.10
|
||||
* Post-quantum signature schemes Dilithium, SPHINCS+, and XMSS
|
||||
* Post-quantum key agreement schemes McEliece and Kyber
|
||||
* ElGamal encryption
|
||||
* Padding schemes OAEP, PSS, PKCS #1 v1.5, X9.31
|
||||
|
||||
Ciphers, hashes, MACs, and checksums
|
||||
----------------------------------------
|
||||
|
||||
* Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, (X)ChaCha20Poly1305
|
||||
* Cipher modes CTR, CBC, XTS, CFB, OFB
|
||||
* Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, DES/3DES, IDEA,
|
||||
Lion, SEED, Serpent, SHACAL2, SM4, Threefish-512, Twofish
|
||||
* Stream ciphers (X)ChaCha20, (X)Salsa20, SHAKE-128, RC4
|
||||
* Hash functions SHA-1, SHA-2, SHA-3, MD5, RIPEMD-160, BLAKE2b,
|
||||
Skein-512, SM3, Streebog, Whirlpool
|
||||
* Password hashing schemes PBKDF2, Argon2, Scrypt, bcrypt
|
||||
* Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, X9.19 DES-MAC
|
||||
* Non-cryptographic checksums Adler32, CRC24, CRC32
|
||||
|
||||
Other Useful Things
|
||||
----------------------------------------
|
||||
|
||||
* Full C++ PKCS #11 API wrapper
|
||||
* Interfaces for TPM v1.2 device access
|
||||
* Simple compression API wrapping zlib, bzip2, and lzma libraries
|
||||
* RNG wrappers for system RNG and hardware RNGs
|
||||
* HMAC_DRBG and entropy collection system for userspace RNGs
|
||||
* SRP-6a password authenticated key exchange
|
||||
* Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C
|
||||
* HOTP and TOTP algorithms
|
||||
* Format preserving encryption scheme FE1
|
||||
* Threshold secret sharing
|
||||
* NIST key wrapping
|
||||
* Boost.Asio compatible TLS client stream
|
@ -1,82 +0,0 @@
|
||||
---
|
||||
# This file was automatically generated by src/scripts/dev_tools/run_clang_tidy.py --regenerate-inline-config-file
|
||||
#
|
||||
# All manual edits to this file will be lost. Edit the script
|
||||
# then regenerate this configuration file.
|
||||
|
||||
Checks: >
|
||||
bugprone-*,
|
||||
cert-*,
|
||||
clang-analyzer-*,
|
||||
cppcoreguidelines-*,
|
||||
hicpp-*,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-*-named-parameter,
|
||||
-*-member-init,
|
||||
-bugprone-lambda-function-name,
|
||||
-bugprone-unchecked-optional-access,
|
||||
-cert-err58-cpp,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-slicing,
|
||||
-hicpp-explicit-conversions,
|
||||
-misc-const-correctness,
|
||||
-misc-redundant-expression,
|
||||
-misc-misplaced-const,
|
||||
-misc-confusable-identifiers,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-pass-by-value,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-inconsistent-declaration-parameter-name,
|
||||
-readability-qualified-auto,
|
||||
-readability-simplify-boolean-expr,
|
||||
-readability-static-accessed-through-instance,
|
||||
-*-array-to-pointer-decay,
|
||||
-*-avoid-c-arrays,
|
||||
-*-else-after-return,
|
||||
-*-function-size,
|
||||
-*-magic-numbers,
|
||||
-*-narrowing-conversions,
|
||||
-*-no-array-decay,
|
||||
-*-use-auto,
|
||||
-*-use-emplace,
|
||||
-*-deprecated-headers,
|
||||
-bugprone-argument-comment,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-pro-type-const-cast,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-hicpp-no-assembler,
|
||||
-hicpp-vararg,
|
||||
-hicpp-signed-bitwise,
|
||||
-misc-no-recursion,
|
||||
-modernize-loop-convert,
|
||||
-modernize-raw-string-literal,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-using,
|
||||
-portability-simd-intrinsics,
|
||||
-readability-container-data-pointer,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-identifier-length,
|
||||
-readability-isolate-declaration,
|
||||
-readability-non-const-parameter,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-suspicious-call-argument,
|
||||
-readability-use-anyofallof,
|
||||
---
|
File diff suppressed because it is too large
Load Diff
@ -1,221 +0,0 @@
|
||||
{
|
||||
"LooseErrorTests": {
|
||||
"AppDataBeforeHandshake": "BoGo expects different error before vs after CCS",
|
||||
"AppDataBeforeHandshake-Empty": "Invalid record message",
|
||||
"ServerHelloBogusCipher": "Unexpected error",
|
||||
"Garbage": "Decoding error",
|
||||
"Resume-Client-CipherMismatch": "Unexpected error",
|
||||
"InvalidECDHPoint-Server": "Unexpected error",
|
||||
"NoSharedCipher": "Unexpected error",
|
||||
"NoSharedCipher-TLS13": "Unexpected error",
|
||||
|
||||
"PartialFinishedWithServerHelloDone": "Unexpected record vs excess handshake data",
|
||||
"HelloRetryRequest-DuplicateCurve-TLS13": "expects 'illegal parameter' but we want to stick with 'decode error'",
|
||||
"HelloRetryRequest-DuplicateCookie-TLS13": "expects 'illegal parameter' but we want to stick with 'decode error'",
|
||||
"EncryptedExtensionsWithKeyShare-TLS13": "expects 'unsupported extension' but RFC requires 'illegal parameter'",
|
||||
"ClientSkipCertificateVerify-TLS13": "would require ambiguous error mapping",
|
||||
"Resume-Client-Mismatch-TLS13-TLS12-TLS": "server requests a downgrade to TLS 1.2, echoing the random session ID during a TLS 1.3 resumption. => error mapping conflict",
|
||||
"ServerAuth-NoFallback-TLS13": "would require ambiguous error mapping"
|
||||
},
|
||||
|
||||
"DisabledTests": {
|
||||
"*TLS1": "No TLS 1.0",
|
||||
"*-TLS1-*": "No TLS 1.0",
|
||||
"*-TLS10-*": "No TLS 1.0",
|
||||
"TLS1-*": "No TLS 1.0",
|
||||
"VersionNegotiation*-TLS": "No TLS 1.0",
|
||||
"VersionNegotiation*-DTLS": "No DTLS 1.0",
|
||||
|
||||
"*TLS11": "No TLS 1.1",
|
||||
"*-TLS11-*": "No TLS 1.1",
|
||||
"TLS11-*": "No TLS 1.1",
|
||||
|
||||
"*RSA_PKCS1_MD5_SHA1": "We do not implement MD5/SHA1 concatenation anyway",
|
||||
"Compliance-fips202205-*": "We do not have explicit support for a FIPS TLS policy",
|
||||
"Compliance-fips-202205-*": "We do not have explicit support for a FIPS TLS policy",
|
||||
"Compliance-wpa-202304-*": "We do not have explicit support for the WPA Enterprise mode",
|
||||
|
||||
"CBCRecordSplitting*": "No need to split CBC records in TLS 1.2",
|
||||
"DelegatedCredentials*": "No support of -delegated-cerdential",
|
||||
|
||||
"*SCSV*": "SCSV is meaningless without TLS 1.0/1.1 support",
|
||||
|
||||
"AllExtensions-*": "Not all extensions are implemented",
|
||||
|
||||
"VersionTolerance-TLS13": "We are not tolerating 0x0400 as Client Hello legacy_version",
|
||||
|
||||
"Server-JDK11-*": "We don't implement JDK-specific workarounds",
|
||||
"Client-RejectJDK11DowngradeRandom": "We don't implement this workaround",
|
||||
"ExportTrafficSecrets-*": "Exporting traffic secrets is not implemented",
|
||||
"TooManyChangeCipherSpec-Client-TLS13": "Limits on the number of CCS are not implemented",
|
||||
"TooManyChangeCipherSpec-Server-TLS13": "Limits on the number of CCS are not implemented",
|
||||
"TooManyKeyUpdates": "Limits on the number of KeyUpdates are not implemented",
|
||||
|
||||
"TLS12SessionID-TLS13": "We don't offer TLS 1.3 when a TLS 1.2 session was found",
|
||||
"Ticket-Forbidden-TLS13": "We don't offer TLS 1.3 when a TLS 1.2 session was found",
|
||||
"Resume-Client-NoResume-TLS12-TLS13-TLS": "We don't offer TLS 1.3 when a TLS 1.2 session was found",
|
||||
"Resume-Client-Mismatch-TLS12-TLS13-TLS": "We don't offer TLS 1.3 when a TLS 1.2 session was found",
|
||||
"Resume-Server-UnofferedCipher-TLS13": "BoringSSL will not allow switching ciphers during TLS 1.3 resumption, we do, though.",
|
||||
|
||||
"HttpGET": "TLS 1.3 server does not detect HTTP",
|
||||
"HttpPOST": "TLS 1.3 server does not detect HTTP",
|
||||
"HttpPUT": "TLS 1.3 server does not detect HTTP",
|
||||
"HttpHEAD": "TLS 1.3 server does not detect HTTP",
|
||||
"HttpCONNECT": "TLS 1.3 server does not detect HTTP",
|
||||
|
||||
"*EarlyData*": "No TLS 1.3 Early Data, yet",
|
||||
"TLS13-TicketAgeSkew-*": "No TLS 1.3 Early Data, yet",
|
||||
"ExportKeyingMaterial-Server-HalfRTT-TLS13": "No TLS 1.3 Early Data, yet",
|
||||
"EarlyDataEnabled*": "No TLS 1.3 Early Data, yet",
|
||||
"EarlyData-Reject0RTT*": "No TLS 1.3 Early Data, yet",
|
||||
"PartialEndOfEarlyDataWithClientHello": "No TLS 1.3 Early Data, yet",
|
||||
|
||||
"SendNoClientCertificateExtensions-TLS13": "-signed-cert-timestamps currently not supported in the shim",
|
||||
"KeyUpdate-RequestACK-UnfinishedWrite": "-read-with-unfinished-write currently not supported in the shim",
|
||||
|
||||
"TLS-ECH*": "No ECH support",
|
||||
"ECH*": "No ECH support",
|
||||
|
||||
"DuplicateCertCompressionExt*": "No support for 1.3 cert compression extension",
|
||||
"CertCompression*-TLS13": "No support for 1.3 cert compression extension",
|
||||
|
||||
"SupportedVersionSelection-TLS12": "We just ignore the version extension in this case",
|
||||
|
||||
"Downgrade-*-Client-Ignore": "Not possible to ignore downgrade indicator",
|
||||
|
||||
"Agree-Digest-SHA1": "No SHA-1 in TLS 1.2",
|
||||
"ServerAuth-SHA1-Fallback-*": "No SHA-1 in TLS 1.2",
|
||||
"*-InvalidSignature-*_SHA1-TLS12": "No SHA-1 in TLS 1.2",
|
||||
"*-Sign-*_SHA1-TLS12": "No SHA-1 in TLS 1.2",
|
||||
"*-Sign-Negotiate-*_SHA1-TLS12": "No SHA-1 in TLS 1.2",
|
||||
"*-VerifyDefault-*_SHA1-TLS12": "No SHA-1 in TLS 1.2",
|
||||
"*-Verify-*_SHA1-TLS12": "No SHA-1 in TLS 1.2",
|
||||
|
||||
"*QUIC*": "No QUIC",
|
||||
"ALPS*": "No ALPS",
|
||||
"ExtraClientEncryptedExtension-TLS-TLS13": "No ALPS",
|
||||
|
||||
"*NPN*": "No support for NPN",
|
||||
"ALPNServer-Preferred-*": "No support for NPN",
|
||||
"*-NextProtocol*": "No support for NPN",
|
||||
|
||||
"*SignedCertificateTimestamp*": "No support for SCT",
|
||||
"*SCT*": "No support for SCT",
|
||||
"Renegotiation-ChangeAuthProperties": "No support for SCT",
|
||||
"UnsolicitedCertificateExtensions-*": "No support for SCT",
|
||||
"IgnoreExtensionsOnIntermediates-TLS13": "No support for SCT",
|
||||
"SendNoExtensionsOnIntermediate-TLS13": "No support for SCT",
|
||||
|
||||
"CertificateVerificationSoftFail*": "Fail, but don't fail... wtf?",
|
||||
|
||||
"*NULL-SHA*": "No support for NULL ciphers",
|
||||
"*WITH_NULL*": "No support for NULL ciphers",
|
||||
"*GREASE*": "No support for GREASE",
|
||||
"*ChannelID*": "No support for ChannelID",
|
||||
"*TokenBinding*": "No support for Token Binding",
|
||||
"ClientHelloPadding": "No support for client hello padding extension",
|
||||
"TLSUnique*": "Not supported",
|
||||
"*CECPQ2*": "Not implemented",
|
||||
"PQExperimentSignal*": "Not implemented",
|
||||
"*P-224*": "P-224 not supported in TLS",
|
||||
"*V2ClientHello*": "No support for SSLv2 client hellos",
|
||||
"*Ed25519*": "Ed25519 not implemented in TLS",
|
||||
"*FalseStart*": "Botan doesn't do false start",
|
||||
"MaxSendFragment*": "Maximum fragment extension not supported",
|
||||
"ExportKeyingMaterial-EmptyContext*": "No support for empty context",
|
||||
|
||||
"Peek-*": "No peek API",
|
||||
"*OldCallback*": "BoringSSL specific API test",
|
||||
"*Renegotiate-Client-Explicit*": "BoringSSL specific API test",
|
||||
"CBCRecordSplittingPartialWrite*": "BoringSSL specific API test",
|
||||
"TicketCallback*": "BoringSSL specific API test",
|
||||
"Server-DDoS*": "BoringSSL specific API test",
|
||||
"RetainOnlySHA256-*": "BoringSSL specific API test",
|
||||
"Renegotiate-Client-UnfinishedWrite": "BoringSSL specific API test",
|
||||
"FailEarlyCallback": "BoringSSL specific API test",
|
||||
|
||||
"NotJustKyberKeyShare": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
|
||||
"KyberKeyShareIncludedSecond": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
|
||||
"KyberKeyShareIncludedThird": "BoringSSL specific policy test (we may offer solo PQ/T groups)",
|
||||
|
||||
"ShimTicketRewritable": "Botan has a different ticket format",
|
||||
"Resume-Server-DeclineCrossVersion*": "Botan has a different ticket format",
|
||||
"Resume-Server-DeclineBadCipher*": "Botan has a different ticket format",
|
||||
"Resume-Server-CipherNotPreferred*": "Botan has a different ticket format",
|
||||
|
||||
"TLS*-NoTicket-NoAccept": "BoGo expects that if ticket is issued stateful resumption is impossible",
|
||||
|
||||
"CheckLeafCurve": "Botan doesn't care what curve an ECDSA cert uses",
|
||||
|
||||
"CertificateVerificationDoesNotFailOnResume*": "Botan doesn't support reverify on resume",
|
||||
"CertificateVerificationFailsOnResume*": "Botan doesn't support reverify on resume",
|
||||
"CertificateVerificationPassesOnResume*": "Botan doesn't support reverify on resume",
|
||||
|
||||
"CipherNegotiation-2": "No support for cipher equivalence classes",
|
||||
"CipherNegotiation-3": "No support for cipher equivalence classes",
|
||||
"CipherNegotiation-4": "No support for cipher equivalence classes",
|
||||
"CipherNegotiation-5": "No support for cipher equivalence classes",
|
||||
"CipherNegotiation-8": "No support for cipher equivalence classes",
|
||||
|
||||
"ALPNServer-SelectEmpty-*": "Botan treats empty ALPN from callback as a decline",
|
||||
|
||||
"AppDataAfterChangeCipherSpec-DTLS*": "BoringSSL DTLS drops out of order AppData, we reject",
|
||||
|
||||
"Resume-Client-NoResume-TLS1-TLS11-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-NoResume-TLS1-TLS12-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-NoResume-TLS11-TLS12-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-NoResume-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version",
|
||||
|
||||
"Resume-Client-Mismatch-TLS1-TLS11-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-Mismatch-TLS1-TLS12-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-Mismatch-TLS11-TLS12-TLS": "BoGo expects resumption attempt sends latest version",
|
||||
"Resume-Client-Mismatch-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version",
|
||||
|
||||
"LooseInitialRecordVersion-TLS12": "Botan is somewhat strict about the record version number",
|
||||
|
||||
"CurveTest-*-Compressed*": "Point compression is supported, which BoGo doesn't expect",
|
||||
"PointFormat-*-MissingUncompressed": "Point compression is supported, which BoGo doesn't expect",
|
||||
|
||||
"RSAPSSSupport-ConfigPSS-NoCerts-TLS12-*": "Needs investigation",
|
||||
"RSAPSSSupport-Default-NoCerts-TLS12-*": "Needs investigation",
|
||||
|
||||
"DTLS-Retransmit*": "Shim needs timeout support",
|
||||
|
||||
"DTLS-StrayRetransmitFinished-ClientFull": "Needs investigation",
|
||||
"DTLS-StrayRetransmitFinished-ServerResume": "Needs investigation",
|
||||
|
||||
"SRTP-Server-IgnoreMKI-*": "Non-empty MKI is rejected (bug)",
|
||||
|
||||
"Renegotiate-Client-Packed": "Packing HelloRequest with Finished loses the HelloRequest (bug)",
|
||||
"SendHalfHelloRequest*PackHandshake": "Packing HelloRequest with Finished loses the HelloRequest (bug)",
|
||||
|
||||
"PartialClientFinishedWithClientHello": "Need to check for buffered messages when CCS (bug)",
|
||||
"SendUnencryptedFinished-DTLS": "Need to check for buffered messages when CCS (bug)",
|
||||
|
||||
"RSAKeyUsage-*-TLS12": "We always enforce key usage",
|
||||
"RSAKeyUsage-Client-WantSignature-GotEncipherment-AlwaysEnforced-TLS13": "We always enforce key usage",
|
||||
|
||||
"AllExtensions-Client-Permute-TLS-TLS12" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"AllExtensions-Client-Permute-DTLS-TLS12" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"EarlyData-WriteAfterEncryptedExtensions" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"EarlyData-WriteAfterServerHello" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CipherMismatch1" : "Requires new shim flags that are NYI (as of March 2023)",
|
||||
"TLS-HintMismatch-CipherMismatch2" : "Requires new shim flags that are NYI (as of March 2023)",
|
||||
"TLS-HintMismatch-ECDHE-Group" : "Requires new shim flags that are NYI (as of March 2023)",
|
||||
"TLS-HintMismatch-SignatureInput" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-KeyShare" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-HandshakerHelloRetryRequest" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-ShimHelloRetryRequest" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-SignatureAlgorithm-TLS*" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-NoTickets1-TLS*" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-NoTickets2-TLS*" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-Version2" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CertificateRequest" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CertificateCompression-HandshakerOnly" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CertificateCompression-ShimOnly" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CertificateCompression-AlgorithmMismatch" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-CertificateCompression-InputMismatch" : "Requires new shim flags that are NYI (as of March 2022)",
|
||||
"TLS-HintMismatch-Version1" : "Requires new shim flags that are NYI (as of March 2022)"
|
||||
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
endian little
|
||||
wordsize 64
|
||||
|
||||
<aliases>
|
||||
axp
|
||||
alphaaxp
|
||||
</aliases>
|
@ -1,21 +0,0 @@
|
||||
endian little
|
||||
family arm
|
||||
|
||||
<aliases>
|
||||
arm
|
||||
armeb
|
||||
armel # For Debian
|
||||
armhf # For Debian
|
||||
evbarm # For NetBSD
|
||||
|
||||
armv7
|
||||
armv7l
|
||||
armv7a
|
||||
armv7-a
|
||||
|
||||
armv8l # For AlpineLinux
|
||||
</aliases>
|
||||
|
||||
<isa_extensions>
|
||||
neon
|
||||
</isa_extensions>
|
@ -1,20 +0,0 @@
|
||||
endian little
|
||||
wordsize 64
|
||||
|
||||
family arm
|
||||
|
||||
<aliases>
|
||||
aarch64
|
||||
aarch64_be
|
||||
armv8
|
||||
armv8-a
|
||||
</aliases>
|
||||
|
||||
<isa_extensions>
|
||||
neon
|
||||
armv8crypto
|
||||
armv8sm3
|
||||
armv8sm4
|
||||
armv8sha3
|
||||
armv8sha512
|
||||
</isa_extensions>
|
@ -1,4 +0,0 @@
|
||||
|
||||
# This target can be used when building an amalgamation which must
|
||||
# be built on multiple architectures, or when targetting a CPU
|
||||
# which the build system doesn't know about.
|
@ -1,8 +0,0 @@
|
||||
<aliases>
|
||||
hp-pa
|
||||
parisc
|
||||
parisc64
|
||||
pa-risc
|
||||
hp-parisc
|
||||
hp-pa-risc
|
||||
</aliases>
|
@ -1,6 +0,0 @@
|
||||
wordsize 64
|
||||
|
||||
<aliases>
|
||||
itanium
|
||||
itanic
|
||||
</aliases>
|
@ -1 +0,0 @@
|
||||
wordsize 64
|
@ -1,3 +0,0 @@
|
||||
family loongarch
|
||||
endian little
|
||||
wordsize 64
|
@ -1,6 +0,0 @@
|
||||
endian big
|
||||
|
||||
<aliases>
|
||||
680x0
|
||||
68k
|
||||
</aliases>
|
@ -1,6 +0,0 @@
|
||||
<aliases>
|
||||
mips
|
||||
mipsbe # RedHat
|
||||
mipsle # RedHat
|
||||
mipsel # Debian
|
||||
</aliases>
|
@ -1,5 +0,0 @@
|
||||
wordsize 64
|
||||
|
||||
<aliases>
|
||||
mips64el
|
||||
</aliases>
|
@ -1,3 +0,0 @@
|
||||
endian big
|
||||
|
||||
family ppc
|
@ -1,12 +0,0 @@
|
||||
endian big
|
||||
|
||||
family ppc
|
||||
|
||||
<aliases>
|
||||
powerpc
|
||||
ppc
|
||||
</aliases>
|
||||
|
||||
<isa_extensions>
|
||||
altivec
|
||||
</isa_extensions>
|
@ -1,18 +0,0 @@
|
||||
endian big
|
||||
|
||||
family ppc
|
||||
wordsize 64
|
||||
|
||||
<aliases>
|
||||
powerpc64
|
||||
powerpc64le
|
||||
ppc64le
|
||||
ppc64el
|
||||
</aliases>
|
||||
|
||||
<isa_extensions>
|
||||
altivec
|
||||
vsx
|
||||
powercrypto
|
||||
power9
|
||||
</isa_extensions>
|
@ -1,2 +0,0 @@
|
||||
family riscv
|
||||
endian little
|
@ -1,3 +0,0 @@
|
||||
family riscv
|
||||
endian little
|
||||
wordsize 64
|
@ -1 +0,0 @@
|
||||
endian big
|
@ -1,2 +0,0 @@
|
||||
endian big
|
||||
wordsize 64
|
@ -1,7 +0,0 @@
|
||||
endian big
|
||||
|
||||
family sparc
|
||||
|
||||
<aliases>
|
||||
sparc
|
||||
</aliases>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user