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$/lib/restbed-4.8" />
|
||||||
<file path="$PROJECT_DIR$/phc-winner-argon2-20190702" />
|
<file path="$PROJECT_DIR$/phc-winner-argon2-20190702" />
|
||||||
</libraryRoots>
|
</libraryRoots>
|
||||||
|
<excludeRoots>
|
||||||
|
<file path="$PROJECT_DIR$/cmake-build-debug" />
|
||||||
|
</excludeRoots>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</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