diff --git a/.gitignore b/.gitignore index 8b89da39..11ab3943 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,8 @@ # User settings *.user macOSPackage/ - -# C++ objects and libs -*.slo -*.lo -*.o -*.a -*.la -*.lai -*.so -*.dll -*.dylib +AmneziaVPN.dmg +AmneziaVPN.exe # Qt-es /.qmake.cache @@ -47,4 +38,5 @@ CMakeLists.txt.user* *.*~ # Certificates -*.p12 \ No newline at end of file +*.p12 + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..6c8fa28b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,27 @@ +variables: + GIT_STRATEGY: clone + +stages: + - build + +build-windows: + stage: build + tags: + - windows + script: + - cmd.exe /k "deploy\windows-env.bat && cd deploy && windows.bat" + artifacts: + name: artifacts-windows + paths: + - AmneziaVPN.exe + +build-macos: + stage: build + tags: + - macos + script: + - cd deploy && ./macos.sh + artifacts: + name: artifacts-macos + paths: + - AmneziaVPN.dmg diff --git a/3rd/QtSsh b/3rd/QtSsh deleted file mode 160000 index 542ee3ad..00000000 --- a/3rd/QtSsh +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 542ee3adbc1b663d8764ea8b219f802beaf8523c diff --git a/AmneziaVPN.pro b/AmneziaVPN.pro new file mode 100644 index 00000000..20bf4844 --- /dev/null +++ b/AmneziaVPN.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = client service platform diff --git a/README.md b/README.md new file mode 100644 index 00000000..d3e925b9 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Amnezia + diff --git a/client/3rd/QtSsh/.gitignore b/client/3rd/QtSsh/.gitignore new file mode 100644 index 00000000..8b89da39 --- /dev/null +++ b/client/3rd/QtSsh/.gitignore @@ -0,0 +1,50 @@ +# User settings +*.user +macOSPackage/ + +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +qrc_*.cpp +ui_*.h +Makefile* +*build-* + +# QtCreator + +*.autosave + +# QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCtreator CMake +CMakeLists.txt.user* + +# MACOS files +.DS_Store +._.DS_Store +._* + +# tmp files +*.*~ + +# Certificates +*.p12 \ No newline at end of file diff --git a/client/3rd/QtSsh/.qmake.conf b/client/3rd/QtSsh/.qmake.conf new file mode 100644 index 00000000..ce80dbea --- /dev/null +++ b/client/3rd/QtSsh/.qmake.conf @@ -0,0 +1,3 @@ +load(qt_build_config) + +MODULE_VERSION = 4.3.1 \ No newline at end of file diff --git a/client/3rd/QtSsh/QtSsh.pro b/client/3rd/QtSsh/QtSsh.pro new file mode 100644 index 00000000..58c33f27 --- /dev/null +++ b/client/3rd/QtSsh/QtSsh.pro @@ -0,0 +1 @@ +load(qt_parts) diff --git a/client/3rd/QtSsh/README.md b/client/3rd/QtSsh/README.md new file mode 100644 index 00000000..57527f05 --- /dev/null +++ b/client/3rd/QtSsh/README.md @@ -0,0 +1,46 @@ +# QSsh + +this project is base on Qt-creator-open-source-4.3.1 +project is at + +`http://code.qt.io/cgit/qt-creator/qt-creator.git/` + +you can download code zip at + +`http://download.qt.io/official_releases/qtcreator/4.3/4.3.1/` + +## Getting Started + +> * For linux user, if your Qt is installed through package manager tools such "apt-get", make sure that you have installed the Qt5 develop package *qtbase5-private-dev* + +### Usage(1): Use QtSsh as Qt5's addon module + +#### Building the module + +> **Note**: Perl is needed in this step. + +* Download the source code. + +* Put the source code in any directory you like + +* Go to top directory of the project in a terminal and run + +``` + qmake + make + make install +``` + +The library, the header files, and others will be installed to your system. + +#### Import the module + +` QT += ssh` + +#### Include Headerfile + +` #include` + +#### Close qtc.ssh log + +` QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")` \ No newline at end of file diff --git a/client/3rd/QtSsh/examples/examples.pro b/client/3rd/QtSsh/examples/examples.pro new file mode 100644 index 00000000..7e0d50af --- /dev/null +++ b/client/3rd/QtSsh/examples/examples.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = gitlab \ No newline at end of file diff --git a/client/3rd/QtSsh/examples/gitlab/Qml.qrc b/client/3rd/QtSsh/examples/gitlab/Qml.qrc new file mode 100644 index 00000000..e23ba047 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/Qml.qrc @@ -0,0 +1,5 @@ + + + Qml/Main.qml + + diff --git a/client/3rd/QtSsh/examples/gitlab/Qml/Main.qml b/client/3rd/QtSsh/examples/gitlab/Qml/Main.qml new file mode 100644 index 00000000..8a20f4d8 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/Qml/Main.qml @@ -0,0 +1,51 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import Ssh 1.0 +Item { + width: 1024 + height: 768 + + TextField { + id: input + x: 104 + y: 44 + width: 482 + height: 40 + implicitWidth: 200 + selectByMouse: true + text: "https://www.zhihu.com" + } + function get(url) { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + console.log(xhr.responseXML, xhr.responseText.toString()) + } else if (xhr.readyState === XMLHttpRequest) { + + } + } + xhr.open('GET', url) + xhr.send() + } + Button { + x: 627 + y: 44 + text: "get" + onClicked: { + get(input.text) + } + } + + Button { + id: button + x: 104 + y: 170 + text: qsTr("Ssh") + onClicked: ssh.connectToHost() + } + Ssh { + id: ssh + } + + +} diff --git a/client/3rd/QtSsh/examples/gitlab/Src/Main.cpp b/client/3rd/QtSsh/examples/gitlab/Src/Main.cpp new file mode 100644 index 00000000..03755b84 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/Src/Main.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include "Ssh.hpp" + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + qmlRegisterType ("Ssh", 1, 0, "Ssh"); + + QQuickView view; + view.setSource(QUrl("qrc:/Qml/Main.qml")); + view.show(); + return app.exec(); +} diff --git a/client/3rd/QtSsh/examples/gitlab/Src/Ssh.cpp b/client/3rd/QtSsh/examples/gitlab/Src/Ssh.cpp new file mode 100644 index 00000000..24731e12 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/Src/Ssh.cpp @@ -0,0 +1,61 @@ +#include "Ssh.hpp" +#include +#include +#include + +Ssh::Ssh(QObject *parent) : QObject(parent) { + //关掉qtc.ssh中的各种打印信息 + QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); + + mParams.host="ftb.autoio.org"; + mParams.userName = "ftb"; + mParams.port = 11122; + + mParams.privateKeyFile = QDir::homePath() + QStringLiteral("/.ssh/id_rsa"); + mParams.timeout = 5; + mParams.authenticationType = SshConnectionParameters::AuthenticationTypePublicKey; + mParams.options = SshIgnoreDefaultProxy; + mParams.hostKeyCheckingMode = SshHostKeyCheckingNone; + + mConnections = std::make_shared(mParams); + connect(mConnections.get(), &SshConnection::error, [&](QSsh::SshError){ + qWarning() << "Error: " << mConnections->errorString(); + }); + connect(mConnections.get(), &SshConnection::connected, [&](){ + qWarning() << "Connected"; + create(); + }); + connect(mConnections.get(), &SshConnection::disconnected, [](){ + qWarning() << "Disconnected"; + }); + connect(mConnections.get(), &SshConnection::dataAvailable, [](const QString &message){ + qWarning() << "Message: " << message; + }); +} + +void Ssh::connectToHost() { + mConnections->connectToHost(); +} + +void Ssh::create() { + mRemoteProcess = mConnections->createRemoteProcess(QString::fromLatin1("/bin/ls -a").toUtf8()); + if (!mRemoteProcess) { + qWarning() << QLatin1String("Error: UnmRemoteProcess SSH connection creates remote process."); + return; + } + connect(mRemoteProcess.data(), &SshRemoteProcess::started, [&](){ + qWarning() << "started"; + }); + connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardOutput, [&](){ + qWarning() << "StandardOutput"; + qWarning() << QString::fromLatin1(mRemoteProcess->readAllStandardOutput()).split('\n'); + }); + connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardError, [&](){ + qWarning() << "StandardError" << mRemoteProcess->readAllStandardError(); + }); + connect(mRemoteProcess.data(), &SshRemoteProcess::closed, [&](int exitStatus){ + qWarning() << "Exit" << exitStatus; + }); + mRemoteProcess->start(); +} + diff --git a/client/3rd/QtSsh/examples/gitlab/Src/Ssh.hpp b/client/3rd/QtSsh/examples/gitlab/Src/Ssh.hpp new file mode 100644 index 00000000..787dda98 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/Src/Ssh.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +using namespace QSsh; + +class Ssh : public QObject { + Q_OBJECT +public: + explicit Ssh(QObject *parent = nullptr); + + Q_INVOKABLE void connectToHost(); + void create(); + +private: + SshConnectionParameters mParams; + std::shared_ptr mConnections; + QSharedPointer mRemoteProcess; +}; + diff --git a/client/3rd/QtSsh/examples/gitlab/gitlab.pro b/client/3rd/QtSsh/examples/gitlab/gitlab.pro new file mode 100644 index 00000000..69d0f553 --- /dev/null +++ b/client/3rd/QtSsh/examples/gitlab/gitlab.pro @@ -0,0 +1,29 @@ +QT += quick network ssh +CONFIG += c++11 +TEMPLATE = app +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +#DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += Src/Main.cpp \ + Src/Ssh.cpp + +RESOURCES += Qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +HEADERS += \ + Src/Ssh.hpp + + diff --git a/client/3rd/QtSsh/src/botan/botan.cpp b/client/3rd/QtSsh/src/botan/botan.cpp new file mode 100644 index 00000000..f5776009 --- /dev/null +++ b/client/3rd/QtSsh/src/botan/botan.cpp @@ -0,0 +1,47176 @@ +/* +* Botan 1.10.2 Amalgamation +* (C) 1999-2011 Jack Lloyd and others +* +* Distributed under the terms of the Botan license +*/ + +#include "botan.h" +#include + +#ifdef Q_OS_WIN +#ifndef NOMINMAX +#define NOMINMAX +#endif +#endif + + +namespace Botan { + +/** +* Represents a DLL or shared object +*/ +class Dynamically_Loaded_Library + { + public: + /** + * Load a DLL (or fail with an exception) + * @param lib_name name or path to a library + * + * If you don't use a full path, the search order will be defined + * by whatever the system linker does by default. Always using fully + * qualified pathnames can help prevent code injection attacks (eg + * via manipulation of LD_LIBRARY_PATH on Linux) + */ + Dynamically_Loaded_Library(const std::string& lib_name); + + /** + * Unload the DLL + * @warning Any pointers returned by resolve()/resolve_symbol() + * should not be used after this destructor runs. + */ + ~Dynamically_Loaded_Library(); + + /** + * Load a symbol (or fail with an exception) + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + void* resolve_symbol(const std::string& symbol); + + /** + * Convenience function for casting symbol to the right type + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + template + T resolve(const std::string& symbol) + { +#if defined(__GNUC__) && __GNUC__ < 4 + return (T)(resolve_symbol(symbol)); +#else + return reinterpret_cast(resolve_symbol(symbol)); +#endif + } + + private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + + std::string lib_name; + void* lib; + }; + +} + +#ifdef Q_OS_WIN +namespace Botan { + +/** +* Win32 Entropy Source +*/ +class Win32_EntropySource : public EntropySource + { + public: + std::string name() const { return "Win32 Statistics"; } + void poll(Entropy_Accumulator& accum); + }; + +} +#endif + +namespace Botan { + +/** +* Fake SIMD, using plain scalar operations +* Often still faster than iterative on superscalar machines +*/ +class SIMD_Scalar + { + public: + static bool enabled() { return true; } + + SIMD_Scalar(const u32bit B[4]) + { + R0 = B[0]; + R1 = B[1]; + R2 = B[2]; + R3 = B[3]; + } + + SIMD_Scalar(u32bit B0, u32bit B1, u32bit B2, u32bit B3) + { + R0 = B0; + R1 = B1; + R2 = B2; + R3 = B3; + } + + SIMD_Scalar(u32bit B) + { + R0 = B; + R1 = B; + R2 = B; + R3 = B; + } + + static SIMD_Scalar load_le(const void* in) + { + const byte* in_b = static_cast(in); + return SIMD_Scalar(Botan::load_le(in_b, 0), + Botan::load_le(in_b, 1), + Botan::load_le(in_b, 2), + Botan::load_le(in_b, 3)); + } + + static SIMD_Scalar load_be(const void* in) + { + const byte* in_b = static_cast(in); + return SIMD_Scalar(Botan::load_be(in_b, 0), + Botan::load_be(in_b, 1), + Botan::load_be(in_b, 2), + Botan::load_be(in_b, 3)); + } + + void store_le(byte out[]) const + { + Botan::store_le(out, R0, R1, R2, R3); + } + + void store_be(byte out[]) const + { + Botan::store_be(out, R0, R1, R2, R3); + } + + void rotate_left(size_t rot) + { + R0 = Botan::rotate_left(R0, rot); + R1 = Botan::rotate_left(R1, rot); + R2 = Botan::rotate_left(R2, rot); + R3 = Botan::rotate_left(R3, rot); + } + + void rotate_right(size_t rot) + { + R0 = Botan::rotate_right(R0, rot); + R1 = Botan::rotate_right(R1, rot); + R2 = Botan::rotate_right(R2, rot); + R3 = Botan::rotate_right(R3, rot); + } + + void operator+=(const SIMD_Scalar& other) + { + R0 += other.R0; + R1 += other.R1; + R2 += other.R2; + R3 += other.R3; + } + + SIMD_Scalar operator+(const SIMD_Scalar& other) const + { + return SIMD_Scalar(R0 + other.R0, + R1 + other.R1, + R2 + other.R2, + R3 + other.R3); + } + + void operator-=(const SIMD_Scalar& other) + { + R0 -= other.R0; + R1 -= other.R1; + R2 -= other.R2; + R3 -= other.R3; + } + + SIMD_Scalar operator-(const SIMD_Scalar& other) const + { + return SIMD_Scalar(R0 - other.R0, + R1 - other.R1, + R2 - other.R2, + R3 - other.R3); + } + + void operator^=(const SIMD_Scalar& other) + { + R0 ^= other.R0; + R1 ^= other.R1; + R2 ^= other.R2; + R3 ^= other.R3; + } + + SIMD_Scalar operator^(const SIMD_Scalar& other) const + { + return SIMD_Scalar(R0 ^ other.R0, + R1 ^ other.R1, + R2 ^ other.R2, + R3 ^ other.R3); + } + + void operator|=(const SIMD_Scalar& other) + { + R0 |= other.R0; + R1 |= other.R1; + R2 |= other.R2; + R3 |= other.R3; + } + + SIMD_Scalar operator&(const SIMD_Scalar& other) + { + return SIMD_Scalar(R0 & other.R0, + R1 & other.R1, + R2 & other.R2, + R3 & other.R3); + } + + void operator&=(const SIMD_Scalar& other) + { + R0 &= other.R0; + R1 &= other.R1; + R2 &= other.R2; + R3 &= other.R3; + } + + SIMD_Scalar operator<<(size_t shift) const + { + return SIMD_Scalar(R0 << shift, + R1 << shift, + R2 << shift, + R3 << shift); + } + + SIMD_Scalar operator>>(size_t shift) const + { + return SIMD_Scalar(R0 >> shift, + R1 >> shift, + R2 >> shift, + R3 >> shift); + } + + SIMD_Scalar operator~() const + { + return SIMD_Scalar(~R0, ~R1, ~R2, ~R3); + } + + // (~reg) & other + SIMD_Scalar andc(const SIMD_Scalar& other) + { + return SIMD_Scalar(~R0 & other.R0, + ~R1 & other.R1, + ~R2 & other.R2, + ~R3 & other.R3); + } + + SIMD_Scalar bswap() const + { + return SIMD_Scalar(reverse_bytes(R0), + reverse_bytes(R1), + reverse_bytes(R2), + reverse_bytes(R3)); + } + + static void transpose(SIMD_Scalar& B0, SIMD_Scalar& B1, + SIMD_Scalar& B2, SIMD_Scalar& B3) + { + SIMD_Scalar T0(B0.R0, B1.R0, B2.R0, B3.R0); + SIMD_Scalar T1(B0.R1, B1.R1, B2.R1, B3.R1); + SIMD_Scalar T2(B0.R2, B1.R2, B2.R2, B3.R2); + SIMD_Scalar T3(B0.R3, B1.R3, B2.R3, B3.R3); + + B0 = T0; + B1 = T1; + B2 = T2; + B3 = T3; + } + + private: + u32bit R0, R1, R2, R3; + }; + +} + + +namespace Botan { + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length +* @param out the input/output buffer +* @param in the read-only input buffer +* @param length the length of the buffers +*/ +inline void xor_buf(byte out[], const byte in[], size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) ^= *reinterpret_cast(in); +#else + out[0] ^= in[0]; out[1] ^= in[1]; + out[2] ^= in[2]; out[3] ^= in[3]; + out[4] ^= in[4]; out[5] ^= in[5]; + out[6] ^= in[6]; out[7] ^= in[7]; +#endif + + out += 8; in += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] ^= in[i]; + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length +* @param out the output buffer +* @param in the first input buffer +* @param in2 the second output buffer +* @param length the length of the three buffers +*/ +inline void xor_buf(byte out[], + const byte in[], + const byte in2[], + size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = + *reinterpret_cast(in) ^ + *reinterpret_cast(in2); +#else + out[0] = in[0] ^ in2[0]; out[1] = in[1] ^ in2[1]; + out[2] = in[2] ^ in2[2]; out[3] = in[3] ^ in2[3]; + out[4] = in[4] ^ in2[4]; out[5] = in[5] ^ in2[5]; + out[6] = in[6] ^ in2[6]; out[7] = in[7] ^ in2[7]; +#endif + + in += 8; in2 += 8; out += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] = in[i] ^ in2[i]; + } + +} + + +namespace Botan { + +/** +* Mutex Base Class +*/ +class Mutex + { + public: + /** + * Lock the mutex + */ + virtual void lock() = 0; + + /** + * Unlock the mutex + */ + virtual void unlock() = 0; + virtual ~Mutex() Q_DECL_NOEXCEPT_EXPR(false) {} + }; + +/** +* Mutex Factory +*/ +class Mutex_Factory + { + public: + /** + * @return newly allocated mutex + */ + virtual Mutex* make() = 0; + + virtual ~Mutex_Factory() {} + }; + +/** +* Mutex Holding Class for RAII +*/ +class Mutex_Holder + { + public: + /** + * Hold onto a mutex until we leave scope + * @param m the mutex to lock + */ + Mutex_Holder(Mutex* m) : mux(m) + { + if(!mux) + throw Invalid_Argument("Mutex_Holder: Argument was NULL"); + mux->lock(); + } + + ~Mutex_Holder() { mux->unlock(); } + private: + Mutex* mux; + }; + +} + + +namespace Botan { + +/** +* Copy-on-Predicate Algorithm +* @param current the first iterator value +* @param end the final iterator value +* @param dest an output iterator +* @param copy_p the predicate +*/ +template +OutputIterator copy_if(InputIterator current, InputIterator end, + OutputIterator dest, Predicate copy_p) + { + while(current != end) + { + if(copy_p(*current)) + *dest++ = *current; + ++current; + } + return dest; + } + +/** +* Searching through a std::map +* @param mapping the map to search +* @param key is what to look for +* @param null_result is the value to return if key is not in mapping +* @return mapping[key] or null_result +*/ +template +inline V search_map(const std::map& mapping, + const K& key, + const V& null_result = V()) + { + typename std::map::const_iterator i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return i->second; + } + +/** +* Function adaptor for delete operation +*/ +template +class del_fun : public std::unary_function + { + public: + void operator()(T* ptr) { delete ptr; } + }; + +/** +* Delete the second half of a pair of objects +*/ +template +void delete2nd(Pair& pair) + { + delete pair.second; + } + +/** +* Insert a key/value pair into a multimap +*/ +template +void multimap_insert(std::multimap& multimap, + const K& key, const V& value) + { +#if defined(BOTAN_BUILD_COMPILER_IS_SUN_STUDIO) + // Work around a strange bug in Sun Studio + multimap.insert(std::make_pair(key, value)); +#else + multimap.insert(std::make_pair(key, value)); +#endif + } + +} + + +namespace Botan { + +/** +* @param prov_name a provider name +* @return weight for this provider +*/ +size_t static_provider_weight(const std::string& prov_name); + +/** +* Algorithm_Cache (used by Algorithm_Factory) +*/ +template +class Algorithm_Cache + { + public: + /** + * @param algo_spec names the requested algorithm + * @param pref_provider suggests a preferred provider + * @return prototype object, or NULL + */ + const T* get(const std::string& algo_spec, + const std::string& pref_provider); + + /** + * Add a new algorithm implementation to the cache + * @param algo the algorithm prototype object + * @param requested_name how this name will be requested + * @param provider_name is the name of the provider of this prototype + */ + void add(T* algo, + const std::string& requested_name, + const std::string& provider_name); + + /** + * Set the preferred provider + * @param algo_spec names the algorithm + * @param provider names the preferred provider + */ + void set_preferred_provider(const std::string& algo_spec, + const std::string& provider); + + /** + * Return the list of providers of this algorithm + * @param algo_name names the algorithm + * @return list of providers of this algorithm + */ + std::vector providers_of(const std::string& algo_name); + + /** + * Clear the cache + */ + void clear_cache(); + + /** + * Constructor + * @param m a mutex to serialize internal access + */ + Algorithm_Cache(Mutex* m) : mutex(m) {} + ~Algorithm_Cache() { clear_cache(); delete mutex; } + private: + typedef typename std::map >::iterator + algorithms_iterator; + + typedef typename std::map::iterator provider_iterator; + + algorithms_iterator find_algorithm(const std::string& algo_spec); + + Mutex* mutex; + std::map aliases; + std::map pref_providers; + std::map > algorithms; + }; + +/* +* Look for an algorithm implementation in the cache, also checking aliases +* Assumes object lock is held +*/ +template +typename Algorithm_Cache::algorithms_iterator +Algorithm_Cache::find_algorithm(const std::string& algo_spec) + { + algorithms_iterator algo = algorithms.find(algo_spec); + + // Not found? Check if a known alias + if(algo == algorithms.end()) + { + std::map::const_iterator alias = + aliases.find(algo_spec); + + if(alias != aliases.end()) + algo = algorithms.find(alias->second); + } + + return algo; + } + +/* +* Look for an algorithm implementation by a particular provider +*/ +template +const T* Algorithm_Cache::get(const std::string& algo_spec, + const std::string& requested_provider) + { + Mutex_Holder lock(mutex); + + algorithms_iterator algo = find_algorithm(algo_spec); + if(algo == algorithms.end()) // algo not found at all (no providers) + return 0; + + // If a provider is requested specifically, return it or fail entirely + if(requested_provider != "") + { + provider_iterator prov = algo->second.find(requested_provider); + if(prov != algo->second.end()) + return prov->second; + return 0; + } + + const T* prototype = 0; + std::string prototype_provider; + size_t prototype_prov_weight = 0; + + const std::string pref_provider = search_map(pref_providers, algo_spec); + + for(provider_iterator i = algo->second.begin(); i != algo->second.end(); ++i) + { + const std::string prov_name = i->first; + const size_t prov_weight = static_provider_weight(prov_name); + + // preferred prov exists, return immediately + if(prov_name == pref_provider) + return i->second; + + if(prototype == 0 || prov_weight > prototype_prov_weight) + { + prototype = i->second; + prototype_provider = i->first; + prototype_prov_weight = prov_weight; + } + } + + return prototype; + } + +/* +* Add an implementation to the cache +*/ +template +void Algorithm_Cache::add(T* algo, + const std::string& requested_name, + const std::string& provider) + { + if(!algo) + return; + + Mutex_Holder lock(mutex); + + if(algo->name() != requested_name && + aliases.find(requested_name) == aliases.end()) + { + aliases[requested_name] = algo->name(); + } + + if(!algorithms[algo->name()][provider]) + algorithms[algo->name()][provider] = algo; + else + delete algo; + } + +/* +* Find the providers of this algo (if any) +*/ +template std::vector +Algorithm_Cache::providers_of(const std::string& algo_name) + { + Mutex_Holder lock(mutex); + + std::vector providers; + + algorithms_iterator algo = find_algorithm(algo_name); + + if(algo != algorithms.end()) + { + provider_iterator provider = algo->second.begin(); + + while(provider != algo->second.end()) + { + providers.push_back(provider->first); + ++provider; + } + } + + return providers; + } + +/* +* Set the preferred provider for an algorithm +*/ +template +void Algorithm_Cache::set_preferred_provider(const std::string& algo_spec, + const std::string& provider) + { + Mutex_Holder lock(mutex); + + pref_providers[algo_spec] = provider; + } + +/* +* Clear out the cache +*/ +template +void Algorithm_Cache::clear_cache() + { + algorithms_iterator algo = algorithms.begin(); + + while(algo != algorithms.end()) + { + provider_iterator provider = algo->second.begin(); + + while(provider != algo->second.end()) + { + delete provider->second; + ++provider; + } + + ++algo; + } + + algorithms.clear(); + } + +} + + +namespace Botan { + +/** +* Round up +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded up to a multiple of align_to +*/ +template +inline T round_up(T n, T align_to) + { + if(n % align_to || n == 0) + n += align_to - (n % align_to); + return n; + } + +/** +* Round down +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded down to a multiple of align_to +*/ +template +inline T round_down(T n, T align_to) + { + return (n - (n % align_to)); + } + +} + + +namespace Botan { + +/** +* Engine for implementations that use some kind of SIMD +*/ +class SIMD_Engine : public Engine + { + public: + std::string provider_name() const { return "simd"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const; + }; + +} + + +namespace Botan { + +/** +* File Tree Walking Entropy Source +*/ +class FTW_EntropySource : public EntropySource + { + public: + std::string name() const { return "Proc Walker"; } + + void poll(Entropy_Accumulator& accum); + + FTW_EntropySource(const std::string& root_dir); + ~FTW_EntropySource(); + private: + std::string path; + class File_Descriptor_Source* dir; + }; + +} + + +namespace Botan { + +/** +* Entropy source using high resolution timers +* +* @note Any results from timers are marked as not contributing entropy +* to the poll, as a local attacker could observe them directly. +*/ +class High_Resolution_Timestamp : public EntropySource + { + public: + std::string name() const { return "High Resolution Timestamp"; } + void poll(Entropy_Accumulator& accum); + }; + +} + +#ifdef Q_OS_WIN +namespace Botan { + +/** +* Win32 Mutex Factory +*/ +class Win32_Mutex_Factory : public Mutex_Factory + { + public: + Mutex* make(); + }; +} +#endif + + +namespace Botan { + +/** +* Power of 2 test. T should be an unsigned integer type +* @param arg an integer value +* @return true iff arg is 2^n for some n > 0 +*/ +template +inline bool power_of_2(T arg) + { + return ((arg != 0 && arg != 1) && ((arg & (arg-1)) == 0)); + } + +/** +* Return the index of the highest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the highest set bit in n +*/ +template +inline size_t high_bit(T n) + { + for(size_t i = 8*sizeof(T); i > 0; --i) + if((n >> (i - 1)) & 0x01) + return i; + return 0; + } + +/** +* Return the index of the lowest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the lowest set bit in n +*/ +template +inline size_t low_bit(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return (i + 1); + return 0; + } + +/** +* Return the number of significant bytes in n +* @param n an integer value +* @return number of significant bytes in n +*/ +template +inline size_t significant_bytes(T n) + { + for(size_t i = 0; i != sizeof(T); ++i) + if(get_byte(i, n)) + return sizeof(T)-i; + return 0; + } + +/** +* Compute Hamming weights +* @param n an integer value +* @return number of bits in n set to 1 +*/ +template +inline size_t hamming_weight(T n) + { + const byte NIBBLE_WEIGHTS[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + + size_t weight = 0; + for(size_t i = 0; i != 2*sizeof(T); ++i) + weight += NIBBLE_WEIGHTS[(n >> (4*i)) & 0x0F]; + return weight; + } + +/** +* Count the trailing zero bits in n +* @param n an integer value +* @return maximum x st 2^x divides n +*/ +template +inline size_t ctz(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return i; + return 8*sizeof(T); + } + +} + + +namespace Botan { + +/** +* Estimate work factor for discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +size_t dl_work_factor(size_t prime_group_size); + +} + + +namespace Botan { + +/** +* No-Op Mutex Factory +*/ +class Noop_Mutex_Factory : public Mutex_Factory + { + public: + Mutex* make(); + }; + +} + + +namespace Botan { + +/** +* Pooling Allocator +*/ +class Pooling_Allocator : public Allocator + { + public: + void* allocate(size_t); + void deallocate(void*, size_t); + + void destroy(); + + /** + * @param mutex used for internal locking + */ + Pooling_Allocator(Mutex* mutex); + ~Pooling_Allocator(); + private: + void get_more_core(size_t); + byte* allocate_blocks(size_t); + + virtual void* alloc_block(size_t) = 0; + virtual void dealloc_block(void*, size_t) = 0; + + class Memory_Block + { + public: + Memory_Block(void*); + + static size_t bitmap_size() { return BITMAP_SIZE; } + static size_t block_size() { return BLOCK_SIZE; } + + bool contains(void*, size_t) const; + byte* alloc(size_t); + void free(void*, size_t); + + bool operator<(const Memory_Block& other) const + { + if(buffer < other.buffer && other.buffer < buffer_end) + return false; + return (buffer < other.buffer); + } + private: + typedef u64bit bitmap_type; + static const size_t BITMAP_SIZE = 8 * sizeof(bitmap_type); + static const size_t BLOCK_SIZE = 64; + + bitmap_type bitmap; + byte* buffer, *buffer_end; + }; + + std::vector blocks; + std::vector::iterator last_used; + std::vector > allocated; + Mutex* mutex; + }; + +} + + +namespace Botan { + +/** +* Allocator using malloc +*/ +class Malloc_Allocator : public Allocator + { + public: + void* allocate(size_t); + void deallocate(void*, size_t); + + std::string type() const { return "malloc"; } + }; + +/** +* Allocator using malloc plus locking +*/ +class Locking_Allocator : public Pooling_Allocator + { + public: + /** + * @param mutex used for internal locking + */ + Locking_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {} + + std::string type() const { return "locking"; } + private: + void* alloc_block(size_t); + void dealloc_block(void*, size_t); + }; + +} + + +namespace Botan { + +/** +* Fixed Window Exponentiator +*/ +class Fixed_Window_Exponentiator : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&); + void set_base(const BigInt&); + BigInt execute() const; + + Modular_Exponentiator* copy() const + { return new Fixed_Window_Exponentiator(*this); } + + Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + Modular_Reducer reducer; + BigInt exp; + size_t window_bits; + std::vector g; + Power_Mod::Usage_Hints hints; + }; + +/** +* Montgomery Exponentiator +*/ +class Montgomery_Exponentiator : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&); + void set_base(const BigInt&); + BigInt execute() const; + + Modular_Exponentiator* copy() const + { return new Montgomery_Exponentiator(*this); } + + Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + BigInt exp, modulus; + BigInt R2, R_mod; + std::vector g; + word mod_prime; + size_t mod_words, exp_bits, window_bits; + Power_Mod::Usage_Hints hints; + }; + +} + + +#if (BOTAN_MP_WORD_BITS != 32) + #error The mp_x86_32 module requires that BOTAN_MP_WORD_BITS == 32 +#endif + +#ifdef Q_OS_UNIX +namespace Botan { + +extern "C" { + +/* +* Helper Macros for x86 Assembly +*/ +#define ASM(x) x "\n\t" + +/* +* Word Multiply +*/ +inline word word_madd2(word a, word b, word* c) + { + asm( + ASM("mull %[b]") + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { + asm( + ASM("mull %[b]") + + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + ASM("addl %[d],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + } + +} + +} +#endif + + + +namespace Botan { + +/** +* Unix Program Info +*/ +struct Unix_Program + { + /** + * @param n is the name and arguments of what we are going run + * @param p is the priority level (lower prio numbers get polled first) + */ + Unix_Program(const char* n, size_t p) + { name_and_args = n; priority = p; working = true; } + + /** + * The name and arguments for this command + */ + std::string name_and_args; + + /** + * Priority: we scan from low to high + */ + size_t priority; + + /** + * Does this source seem to be working? + */ + bool working; + }; + +/** +* Command Output DataSource +*/ +class DataSource_Command : public DataSource + { + public: + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t) const; + bool end_of_data() const; + std::string id() const; + + int fd() const; + + DataSource_Command(const std::string&, + const std::vector& paths); + ~DataSource_Command(); + private: + void create_pipe(const std::vector&); + void shutdown_pipe(); + + const size_t MAX_BLOCK_USECS, KILL_WAIT; + + std::vector arg_list; + struct pipe_wrapper* pipe; + }; + +} + + +namespace Botan { + +/** +* Allocator that uses memory maps backed by disk. We zeroize the map +* upon deallocation. If swap occurs, the VM will swap to the shared +* file backing rather than to a swap device, which means we know where +* it is and can zap it later. +*/ +class MemoryMapping_Allocator : public Pooling_Allocator + { + public: + /** + * @param mutex used for internal locking + */ + MemoryMapping_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {} + std::string type() const { return "mmap"; } + private: + void* alloc_block(size_t); + void dealloc_block(void*, size_t); + }; + +} + + +#if defined(BOTAN_HAS_SIMD_SSE2) + namespace Botan { typedef SIMD_SSE2 SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_ALTIVEC) + namespace Botan { typedef SIMD_Altivec SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_SCALAR) + namespace Botan { typedef SIMD_Scalar SIMD_32; } + +#else + #error "No SIMD module defined" + +#endif + + +namespace Botan { + +/** +* Entropy source reading from kernel devices like /dev/random +*/ +class Device_EntropySource : public EntropySource + { + public: + std::string name() const { return "RNG Device Reader"; } + + void poll(Entropy_Accumulator& accum); + + Device_EntropySource(const std::vector& fsnames); + ~Device_EntropySource(); + private: + + /** + A class handling reading from a Unix character device + */ + class Device_Reader + { + public: + typedef int fd_type; + + // Does not own fd, a transient class + Device_Reader(fd_type device_fd) : fd(device_fd) {} + + void close(); + + size_t get(byte out[], size_t length, size_t ms_wait_time); + + static fd_type open(const std::string& pathname); + private: + fd_type fd; + }; + + std::vector devices; + }; + +} + +namespace Botan { + +void assertion_failure(const char* expr_str, + const char* msg, + const char* func, + const char* file, + int line); + +#define BOTAN_ASSERT(expr, msg) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + msg, \ + BOTAN_ASSERT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +#define BOTAN_ASSERT_EQUAL(value1, value2, msg) \ + do { \ + if(value1 != value2) \ + Botan::assertion_failure(#value1 " == " #value2, \ + msg, \ + BOTAN_ASSERT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/* +* Unfortunately getting the function name from the preprocessor +* isn't standard in C++98 (C++0x uses C99's __func__) +*/ +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || \ + defined(BOTAN_BUILD_COMPILER_IS_CLANG) || \ + defined(BOTAN_BUILD_COMPILER_IS_INTEL) + + #define BOTAN_ASSERT_FUNCTION __PRETTY_FUNCTION__ + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + + #define BOTAN_ASSERT_FUNCTION __FUNCTION__ + +#else + #define BOTAN_ASSERT_FUNCTION ((const char*)0) +#endif + +} + + +namespace Botan { + +/* +* The size of the word type, in bits +*/ +const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS; + +extern "C" { + +/* +* Addition/Subtraction Operations +*/ +void bigint_add2(word x[], size_t x_size, + const word y[], size_t y_size); + +void bigint_add3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size); + +word bigint_add3_nc(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +word bigint_sub2(word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* x = y - x; assumes y >= x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size); + +word bigint_sub3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/* +* Shift Operations +*/ +void bigint_shl1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +/* +* Simple O(N^2) Multiplication and Squaring +*/ +void bigint_simple_mul(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +void bigint_simple_sqr(word z[], const word x[], size_t x_size); + +/* +* Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y); +void bigint_linmul3(word z[], const word x[], size_t x_size, word y); + +/** +* Montgomery Reduction +* @param z integer to reduce (also output in first p_size+1 words) +* @param z_size size of z (should be >= 2*p_size+1) +* @param p modulus +* @param p_size size of p +* @param p_dash Montgomery value +* @param workspace array of at least 2*(p_size+1) words +*/ +void bigint_monty_redc(word z[], size_t z_size, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Montgomery Multiplication +*/ +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Montgomery Squaring +*/ +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Division operation +*/ +size_t bigint_divcore(word q, word y2, word y1, + word x3, word x2, word x1); + +/** +* Compare x and y +*/ +s32bit bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Compute ((n1<& path); + private: + static std::vector get_default_sources(); + void fast_poll(Entropy_Accumulator& accum); + + const std::vector PATH; + std::vector sources; + }; + +} + +namespace Botan { + +/** +* EGD Entropy Source +*/ +class EGD_EntropySource : public EntropySource + { + public: + std::string name() const { return "EGD/PRNGD"; } + + void poll(Entropy_Accumulator& accum); + + EGD_EntropySource(const std::vector&); + ~EGD_EntropySource(); + private: + class EGD_Socket + { + public: + EGD_Socket(const std::string& path); + + void close(); + size_t read(byte outbuf[], size_t length); + private: + static int open_socket(const std::string& path); + + std::string socket_path; + int m_fd; // cached fd + }; + + std::vector sockets; + }; + +} +#endif + +namespace Botan { + +Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + +Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng); + +} + + +namespace Botan { + +/** +* Container of output buffers for Pipe +*/ +class Output_Buffers + { + public: + size_t read(byte[], size_t, Pipe::message_id); + size_t peek(byte[], size_t, size_t, Pipe::message_id) const; + size_t remaining(Pipe::message_id) const; + + void add(class SecureQueue*); + void retire(); + + Pipe::message_id message_count() const; + + Output_Buffers(); + ~Output_Buffers(); + private: + class SecureQueue* get(Pipe::message_id) const; + + std::deque buffers; + Pipe::message_id offset; + }; + +} + + +namespace Botan { + +/** +* Check if we can at least potentially lock memory +*/ +bool has_mlock(); + +/** +* Lock memory into RAM if possible +* @param addr the start of the memory block +* @param length the length of the memory block in bytes +* @returns true if successful, false otherwise +*/ +bool lock_mem(void* addr, size_t length); + +/** +* Unlock memory locked with lock_mem() +* @param addr the start of the memory block +* @param length the length of the memory block in bytes +*/ +void unlock_mem(void* addr, size_t length); + +} + +#ifdef Q_OS_WIN +#if (BOTAN_MP_WORD_BITS == 8) + typedef Botan::u16bit dword; +#elif (BOTAN_MP_WORD_BITS == 16) + typedef Botan::u32bit dword; +#elif (BOTAN_MP_WORD_BITS == 32) + typedef Botan::u64bit dword; +#elif (BOTAN_MP_WORD_BITS == 64) + #error BOTAN_MP_WORD_BITS can be 64 only with assembly support +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +namespace Botan { + +extern "C" { + +/* +* Word Multiply/Add +*/ +inline word word_madd2(word a, word b, word* c) + { + dword z = (dword)a * b + *c; + *c = (word)(z >> BOTAN_MP_WORD_BITS); + return (word)z; + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { + dword z = (dword)a * b + c + *d; + *d = (word)(z >> BOTAN_MP_WORD_BITS); + return (word)z; + } + +} + +/** +* Win32 CAPI Entropy Source +*/ +class Win32_CAPI_EntropySource : public EntropySource + { + public: + std::string name() const { return "Win32 CryptoGenRandom"; } + + void poll(Entropy_Accumulator& accum); + + /** + * Win32_Capi_Entropysource Constructor + * @param provs list of providers, separated by ':' + */ + Win32_CAPI_EntropySource(const std::string& provs = ""); + private: + std::vector prov_types; + }; + +} +#endif + + +namespace Botan { + +template +inline void prefetch_readonly(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 0); +#endif + } + +template +inline void prefetch_readwrite(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 1); +#endif + } + +} + + +namespace Botan { + +const u64bit Camellia_SBOX1[256] = { +0x7070700070000070ULL, 0x8282820082000082ULL, 0x2C2C2C002C00002CULL, 0xECECEC00EC0000ECULL, +0xB3B3B300B30000B3ULL, 0x2727270027000027ULL, 0xC0C0C000C00000C0ULL, 0xE5E5E500E50000E5ULL, +0xE4E4E400E40000E4ULL, 0x8585850085000085ULL, 0x5757570057000057ULL, 0x3535350035000035ULL, +0xEAEAEA00EA0000EAULL, 0x0C0C0C000C00000CULL, 0xAEAEAE00AE0000AEULL, 0x4141410041000041ULL, +0x2323230023000023ULL, 0xEFEFEF00EF0000EFULL, 0x6B6B6B006B00006BULL, 0x9393930093000093ULL, +0x4545450045000045ULL, 0x1919190019000019ULL, 0xA5A5A500A50000A5ULL, 0x2121210021000021ULL, +0xEDEDED00ED0000EDULL, 0x0E0E0E000E00000EULL, 0x4F4F4F004F00004FULL, 0x4E4E4E004E00004EULL, +0x1D1D1D001D00001DULL, 0x6565650065000065ULL, 0x9292920092000092ULL, 0xBDBDBD00BD0000BDULL, +0x8686860086000086ULL, 0xB8B8B800B80000B8ULL, 0xAFAFAF00AF0000AFULL, 0x8F8F8F008F00008FULL, +0x7C7C7C007C00007CULL, 0xEBEBEB00EB0000EBULL, 0x1F1F1F001F00001FULL, 0xCECECE00CE0000CEULL, +0x3E3E3E003E00003EULL, 0x3030300030000030ULL, 0xDCDCDC00DC0000DCULL, 0x5F5F5F005F00005FULL, +0x5E5E5E005E00005EULL, 0xC5C5C500C50000C5ULL, 0x0B0B0B000B00000BULL, 0x1A1A1A001A00001AULL, +0xA6A6A600A60000A6ULL, 0xE1E1E100E10000E1ULL, 0x3939390039000039ULL, 0xCACACA00CA0000CAULL, +0xD5D5D500D50000D5ULL, 0x4747470047000047ULL, 0x5D5D5D005D00005DULL, 0x3D3D3D003D00003DULL, +0xD9D9D900D90000D9ULL, 0x0101010001000001ULL, 0x5A5A5A005A00005AULL, 0xD6D6D600D60000D6ULL, +0x5151510051000051ULL, 0x5656560056000056ULL, 0x6C6C6C006C00006CULL, 0x4D4D4D004D00004DULL, +0x8B8B8B008B00008BULL, 0x0D0D0D000D00000DULL, 0x9A9A9A009A00009AULL, 0x6666660066000066ULL, +0xFBFBFB00FB0000FBULL, 0xCCCCCC00CC0000CCULL, 0xB0B0B000B00000B0ULL, 0x2D2D2D002D00002DULL, +0x7474740074000074ULL, 0x1212120012000012ULL, 0x2B2B2B002B00002BULL, 0x2020200020000020ULL, +0xF0F0F000F00000F0ULL, 0xB1B1B100B10000B1ULL, 0x8484840084000084ULL, 0x9999990099000099ULL, +0xDFDFDF00DF0000DFULL, 0x4C4C4C004C00004CULL, 0xCBCBCB00CB0000CBULL, 0xC2C2C200C20000C2ULL, +0x3434340034000034ULL, 0x7E7E7E007E00007EULL, 0x7676760076000076ULL, 0x0505050005000005ULL, +0x6D6D6D006D00006DULL, 0xB7B7B700B70000B7ULL, 0xA9A9A900A90000A9ULL, 0x3131310031000031ULL, +0xD1D1D100D10000D1ULL, 0x1717170017000017ULL, 0x0404040004000004ULL, 0xD7D7D700D70000D7ULL, +0x1414140014000014ULL, 0x5858580058000058ULL, 0x3A3A3A003A00003AULL, 0x6161610061000061ULL, +0xDEDEDE00DE0000DEULL, 0x1B1B1B001B00001BULL, 0x1111110011000011ULL, 0x1C1C1C001C00001CULL, +0x3232320032000032ULL, 0x0F0F0F000F00000FULL, 0x9C9C9C009C00009CULL, 0x1616160016000016ULL, +0x5353530053000053ULL, 0x1818180018000018ULL, 0xF2F2F200F20000F2ULL, 0x2222220022000022ULL, +0xFEFEFE00FE0000FEULL, 0x4444440044000044ULL, 0xCFCFCF00CF0000CFULL, 0xB2B2B200B20000B2ULL, +0xC3C3C300C30000C3ULL, 0xB5B5B500B50000B5ULL, 0x7A7A7A007A00007AULL, 0x9191910091000091ULL, +0x2424240024000024ULL, 0x0808080008000008ULL, 0xE8E8E800E80000E8ULL, 0xA8A8A800A80000A8ULL, +0x6060600060000060ULL, 0xFCFCFC00FC0000FCULL, 0x6969690069000069ULL, 0x5050500050000050ULL, +0xAAAAAA00AA0000AAULL, 0xD0D0D000D00000D0ULL, 0xA0A0A000A00000A0ULL, 0x7D7D7D007D00007DULL, +0xA1A1A100A10000A1ULL, 0x8989890089000089ULL, 0x6262620062000062ULL, 0x9797970097000097ULL, +0x5454540054000054ULL, 0x5B5B5B005B00005BULL, 0x1E1E1E001E00001EULL, 0x9595950095000095ULL, +0xE0E0E000E00000E0ULL, 0xFFFFFF00FF0000FFULL, 0x6464640064000064ULL, 0xD2D2D200D20000D2ULL, +0x1010100010000010ULL, 0xC4C4C400C40000C4ULL, 0x0000000000000000ULL, 0x4848480048000048ULL, +0xA3A3A300A30000A3ULL, 0xF7F7F700F70000F7ULL, 0x7575750075000075ULL, 0xDBDBDB00DB0000DBULL, +0x8A8A8A008A00008AULL, 0x0303030003000003ULL, 0xE6E6E600E60000E6ULL, 0xDADADA00DA0000DAULL, +0x0909090009000009ULL, 0x3F3F3F003F00003FULL, 0xDDDDDD00DD0000DDULL, 0x9494940094000094ULL, +0x8787870087000087ULL, 0x5C5C5C005C00005CULL, 0x8383830083000083ULL, 0x0202020002000002ULL, +0xCDCDCD00CD0000CDULL, 0x4A4A4A004A00004AULL, 0x9090900090000090ULL, 0x3333330033000033ULL, +0x7373730073000073ULL, 0x6767670067000067ULL, 0xF6F6F600F60000F6ULL, 0xF3F3F300F30000F3ULL, +0x9D9D9D009D00009DULL, 0x7F7F7F007F00007FULL, 0xBFBFBF00BF0000BFULL, 0xE2E2E200E20000E2ULL, +0x5252520052000052ULL, 0x9B9B9B009B00009BULL, 0xD8D8D800D80000D8ULL, 0x2626260026000026ULL, +0xC8C8C800C80000C8ULL, 0x3737370037000037ULL, 0xC6C6C600C60000C6ULL, 0x3B3B3B003B00003BULL, +0x8181810081000081ULL, 0x9696960096000096ULL, 0x6F6F6F006F00006FULL, 0x4B4B4B004B00004BULL, +0x1313130013000013ULL, 0xBEBEBE00BE0000BEULL, 0x6363630063000063ULL, 0x2E2E2E002E00002EULL, +0xE9E9E900E90000E9ULL, 0x7979790079000079ULL, 0xA7A7A700A70000A7ULL, 0x8C8C8C008C00008CULL, +0x9F9F9F009F00009FULL, 0x6E6E6E006E00006EULL, 0xBCBCBC00BC0000BCULL, 0x8E8E8E008E00008EULL, +0x2929290029000029ULL, 0xF5F5F500F50000F5ULL, 0xF9F9F900F90000F9ULL, 0xB6B6B600B60000B6ULL, +0x2F2F2F002F00002FULL, 0xFDFDFD00FD0000FDULL, 0xB4B4B400B40000B4ULL, 0x5959590059000059ULL, +0x7878780078000078ULL, 0x9898980098000098ULL, 0x0606060006000006ULL, 0x6A6A6A006A00006AULL, +0xE7E7E700E70000E7ULL, 0x4646460046000046ULL, 0x7171710071000071ULL, 0xBABABA00BA0000BAULL, +0xD4D4D400D40000D4ULL, 0x2525250025000025ULL, 0xABABAB00AB0000ABULL, 0x4242420042000042ULL, +0x8888880088000088ULL, 0xA2A2A200A20000A2ULL, 0x8D8D8D008D00008DULL, 0xFAFAFA00FA0000FAULL, +0x7272720072000072ULL, 0x0707070007000007ULL, 0xB9B9B900B90000B9ULL, 0x5555550055000055ULL, +0xF8F8F800F80000F8ULL, 0xEEEEEE00EE0000EEULL, 0xACACAC00AC0000ACULL, 0x0A0A0A000A00000AULL, +0x3636360036000036ULL, 0x4949490049000049ULL, 0x2A2A2A002A00002AULL, 0x6868680068000068ULL, +0x3C3C3C003C00003CULL, 0x3838380038000038ULL, 0xF1F1F100F10000F1ULL, 0xA4A4A400A40000A4ULL, +0x4040400040000040ULL, 0x2828280028000028ULL, 0xD3D3D300D30000D3ULL, 0x7B7B7B007B00007BULL, +0xBBBBBB00BB0000BBULL, 0xC9C9C900C90000C9ULL, 0x4343430043000043ULL, 0xC1C1C100C10000C1ULL, +0x1515150015000015ULL, 0xE3E3E300E30000E3ULL, 0xADADAD00AD0000ADULL, 0xF4F4F400F40000F4ULL, +0x7777770077000077ULL, 0xC7C7C700C70000C7ULL, 0x8080800080000080ULL, 0x9E9E9E009E00009EULL }; + +const u64bit Camellia_SBOX2[256] = { +0x00E0E0E0E0E00000ULL, 0x0005050505050000ULL, 0x0058585858580000ULL, 0x00D9D9D9D9D90000ULL, +0x0067676767670000ULL, 0x004E4E4E4E4E0000ULL, 0x0081818181810000ULL, 0x00CBCBCBCBCB0000ULL, +0x00C9C9C9C9C90000ULL, 0x000B0B0B0B0B0000ULL, 0x00AEAEAEAEAE0000ULL, 0x006A6A6A6A6A0000ULL, +0x00D5D5D5D5D50000ULL, 0x0018181818180000ULL, 0x005D5D5D5D5D0000ULL, 0x0082828282820000ULL, +0x0046464646460000ULL, 0x00DFDFDFDFDF0000ULL, 0x00D6D6D6D6D60000ULL, 0x0027272727270000ULL, +0x008A8A8A8A8A0000ULL, 0x0032323232320000ULL, 0x004B4B4B4B4B0000ULL, 0x0042424242420000ULL, +0x00DBDBDBDBDB0000ULL, 0x001C1C1C1C1C0000ULL, 0x009E9E9E9E9E0000ULL, 0x009C9C9C9C9C0000ULL, +0x003A3A3A3A3A0000ULL, 0x00CACACACACA0000ULL, 0x0025252525250000ULL, 0x007B7B7B7B7B0000ULL, +0x000D0D0D0D0D0000ULL, 0x0071717171710000ULL, 0x005F5F5F5F5F0000ULL, 0x001F1F1F1F1F0000ULL, +0x00F8F8F8F8F80000ULL, 0x00D7D7D7D7D70000ULL, 0x003E3E3E3E3E0000ULL, 0x009D9D9D9D9D0000ULL, +0x007C7C7C7C7C0000ULL, 0x0060606060600000ULL, 0x00B9B9B9B9B90000ULL, 0x00BEBEBEBEBE0000ULL, +0x00BCBCBCBCBC0000ULL, 0x008B8B8B8B8B0000ULL, 0x0016161616160000ULL, 0x0034343434340000ULL, +0x004D4D4D4D4D0000ULL, 0x00C3C3C3C3C30000ULL, 0x0072727272720000ULL, 0x0095959595950000ULL, +0x00ABABABABAB0000ULL, 0x008E8E8E8E8E0000ULL, 0x00BABABABABA0000ULL, 0x007A7A7A7A7A0000ULL, +0x00B3B3B3B3B30000ULL, 0x0002020202020000ULL, 0x00B4B4B4B4B40000ULL, 0x00ADADADADAD0000ULL, +0x00A2A2A2A2A20000ULL, 0x00ACACACACAC0000ULL, 0x00D8D8D8D8D80000ULL, 0x009A9A9A9A9A0000ULL, +0x0017171717170000ULL, 0x001A1A1A1A1A0000ULL, 0x0035353535350000ULL, 0x00CCCCCCCCCC0000ULL, +0x00F7F7F7F7F70000ULL, 0x0099999999990000ULL, 0x0061616161610000ULL, 0x005A5A5A5A5A0000ULL, +0x00E8E8E8E8E80000ULL, 0x0024242424240000ULL, 0x0056565656560000ULL, 0x0040404040400000ULL, +0x00E1E1E1E1E10000ULL, 0x0063636363630000ULL, 0x0009090909090000ULL, 0x0033333333330000ULL, +0x00BFBFBFBFBF0000ULL, 0x0098989898980000ULL, 0x0097979797970000ULL, 0x0085858585850000ULL, +0x0068686868680000ULL, 0x00FCFCFCFCFC0000ULL, 0x00ECECECECEC0000ULL, 0x000A0A0A0A0A0000ULL, +0x00DADADADADA0000ULL, 0x006F6F6F6F6F0000ULL, 0x0053535353530000ULL, 0x0062626262620000ULL, +0x00A3A3A3A3A30000ULL, 0x002E2E2E2E2E0000ULL, 0x0008080808080000ULL, 0x00AFAFAFAFAF0000ULL, +0x0028282828280000ULL, 0x00B0B0B0B0B00000ULL, 0x0074747474740000ULL, 0x00C2C2C2C2C20000ULL, +0x00BDBDBDBDBD0000ULL, 0x0036363636360000ULL, 0x0022222222220000ULL, 0x0038383838380000ULL, +0x0064646464640000ULL, 0x001E1E1E1E1E0000ULL, 0x0039393939390000ULL, 0x002C2C2C2C2C0000ULL, +0x00A6A6A6A6A60000ULL, 0x0030303030300000ULL, 0x00E5E5E5E5E50000ULL, 0x0044444444440000ULL, +0x00FDFDFDFDFD0000ULL, 0x0088888888880000ULL, 0x009F9F9F9F9F0000ULL, 0x0065656565650000ULL, +0x0087878787870000ULL, 0x006B6B6B6B6B0000ULL, 0x00F4F4F4F4F40000ULL, 0x0023232323230000ULL, +0x0048484848480000ULL, 0x0010101010100000ULL, 0x00D1D1D1D1D10000ULL, 0x0051515151510000ULL, +0x00C0C0C0C0C00000ULL, 0x00F9F9F9F9F90000ULL, 0x00D2D2D2D2D20000ULL, 0x00A0A0A0A0A00000ULL, +0x0055555555550000ULL, 0x00A1A1A1A1A10000ULL, 0x0041414141410000ULL, 0x00FAFAFAFAFA0000ULL, +0x0043434343430000ULL, 0x0013131313130000ULL, 0x00C4C4C4C4C40000ULL, 0x002F2F2F2F2F0000ULL, +0x00A8A8A8A8A80000ULL, 0x00B6B6B6B6B60000ULL, 0x003C3C3C3C3C0000ULL, 0x002B2B2B2B2B0000ULL, +0x00C1C1C1C1C10000ULL, 0x00FFFFFFFFFF0000ULL, 0x00C8C8C8C8C80000ULL, 0x00A5A5A5A5A50000ULL, +0x0020202020200000ULL, 0x0089898989890000ULL, 0x0000000000000000ULL, 0x0090909090900000ULL, +0x0047474747470000ULL, 0x00EFEFEFEFEF0000ULL, 0x00EAEAEAEAEA0000ULL, 0x00B7B7B7B7B70000ULL, +0x0015151515150000ULL, 0x0006060606060000ULL, 0x00CDCDCDCDCD0000ULL, 0x00B5B5B5B5B50000ULL, +0x0012121212120000ULL, 0x007E7E7E7E7E0000ULL, 0x00BBBBBBBBBB0000ULL, 0x0029292929290000ULL, +0x000F0F0F0F0F0000ULL, 0x00B8B8B8B8B80000ULL, 0x0007070707070000ULL, 0x0004040404040000ULL, +0x009B9B9B9B9B0000ULL, 0x0094949494940000ULL, 0x0021212121210000ULL, 0x0066666666660000ULL, +0x00E6E6E6E6E60000ULL, 0x00CECECECECE0000ULL, 0x00EDEDEDEDED0000ULL, 0x00E7E7E7E7E70000ULL, +0x003B3B3B3B3B0000ULL, 0x00FEFEFEFEFE0000ULL, 0x007F7F7F7F7F0000ULL, 0x00C5C5C5C5C50000ULL, +0x00A4A4A4A4A40000ULL, 0x0037373737370000ULL, 0x00B1B1B1B1B10000ULL, 0x004C4C4C4C4C0000ULL, +0x0091919191910000ULL, 0x006E6E6E6E6E0000ULL, 0x008D8D8D8D8D0000ULL, 0x0076767676760000ULL, +0x0003030303030000ULL, 0x002D2D2D2D2D0000ULL, 0x00DEDEDEDEDE0000ULL, 0x0096969696960000ULL, +0x0026262626260000ULL, 0x007D7D7D7D7D0000ULL, 0x00C6C6C6C6C60000ULL, 0x005C5C5C5C5C0000ULL, +0x00D3D3D3D3D30000ULL, 0x00F2F2F2F2F20000ULL, 0x004F4F4F4F4F0000ULL, 0x0019191919190000ULL, +0x003F3F3F3F3F0000ULL, 0x00DCDCDCDCDC0000ULL, 0x0079797979790000ULL, 0x001D1D1D1D1D0000ULL, +0x0052525252520000ULL, 0x00EBEBEBEBEB0000ULL, 0x00F3F3F3F3F30000ULL, 0x006D6D6D6D6D0000ULL, +0x005E5E5E5E5E0000ULL, 0x00FBFBFBFBFB0000ULL, 0x0069696969690000ULL, 0x00B2B2B2B2B20000ULL, +0x00F0F0F0F0F00000ULL, 0x0031313131310000ULL, 0x000C0C0C0C0C0000ULL, 0x00D4D4D4D4D40000ULL, +0x00CFCFCFCFCF0000ULL, 0x008C8C8C8C8C0000ULL, 0x00E2E2E2E2E20000ULL, 0x0075757575750000ULL, +0x00A9A9A9A9A90000ULL, 0x004A4A4A4A4A0000ULL, 0x0057575757570000ULL, 0x0084848484840000ULL, +0x0011111111110000ULL, 0x0045454545450000ULL, 0x001B1B1B1B1B0000ULL, 0x00F5F5F5F5F50000ULL, +0x00E4E4E4E4E40000ULL, 0x000E0E0E0E0E0000ULL, 0x0073737373730000ULL, 0x00AAAAAAAAAA0000ULL, +0x00F1F1F1F1F10000ULL, 0x00DDDDDDDDDD0000ULL, 0x0059595959590000ULL, 0x0014141414140000ULL, +0x006C6C6C6C6C0000ULL, 0x0092929292920000ULL, 0x0054545454540000ULL, 0x00D0D0D0D0D00000ULL, +0x0078787878780000ULL, 0x0070707070700000ULL, 0x00E3E3E3E3E30000ULL, 0x0049494949490000ULL, +0x0080808080800000ULL, 0x0050505050500000ULL, 0x00A7A7A7A7A70000ULL, 0x00F6F6F6F6F60000ULL, +0x0077777777770000ULL, 0x0093939393930000ULL, 0x0086868686860000ULL, 0x0083838383830000ULL, +0x002A2A2A2A2A0000ULL, 0x00C7C7C7C7C70000ULL, 0x005B5B5B5B5B0000ULL, 0x00E9E9E9E9E90000ULL, +0x00EEEEEEEEEE0000ULL, 0x008F8F8F8F8F0000ULL, 0x0001010101010000ULL, 0x003D3D3D3D3D0000ULL }; + +const u64bit Camellia_SBOX3[256] = { +0x3800383800383800ULL, 0x4100414100414100ULL, 0x1600161600161600ULL, 0x7600767600767600ULL, +0xD900D9D900D9D900ULL, 0x9300939300939300ULL, 0x6000606000606000ULL, 0xF200F2F200F2F200ULL, +0x7200727200727200ULL, 0xC200C2C200C2C200ULL, 0xAB00ABAB00ABAB00ULL, 0x9A009A9A009A9A00ULL, +0x7500757500757500ULL, 0x0600060600060600ULL, 0x5700575700575700ULL, 0xA000A0A000A0A000ULL, +0x9100919100919100ULL, 0xF700F7F700F7F700ULL, 0xB500B5B500B5B500ULL, 0xC900C9C900C9C900ULL, +0xA200A2A200A2A200ULL, 0x8C008C8C008C8C00ULL, 0xD200D2D200D2D200ULL, 0x9000909000909000ULL, +0xF600F6F600F6F600ULL, 0x0700070700070700ULL, 0xA700A7A700A7A700ULL, 0x2700272700272700ULL, +0x8E008E8E008E8E00ULL, 0xB200B2B200B2B200ULL, 0x4900494900494900ULL, 0xDE00DEDE00DEDE00ULL, +0x4300434300434300ULL, 0x5C005C5C005C5C00ULL, 0xD700D7D700D7D700ULL, 0xC700C7C700C7C700ULL, +0x3E003E3E003E3E00ULL, 0xF500F5F500F5F500ULL, 0x8F008F8F008F8F00ULL, 0x6700676700676700ULL, +0x1F001F1F001F1F00ULL, 0x1800181800181800ULL, 0x6E006E6E006E6E00ULL, 0xAF00AFAF00AFAF00ULL, +0x2F002F2F002F2F00ULL, 0xE200E2E200E2E200ULL, 0x8500858500858500ULL, 0x0D000D0D000D0D00ULL, +0x5300535300535300ULL, 0xF000F0F000F0F000ULL, 0x9C009C9C009C9C00ULL, 0x6500656500656500ULL, +0xEA00EAEA00EAEA00ULL, 0xA300A3A300A3A300ULL, 0xAE00AEAE00AEAE00ULL, 0x9E009E9E009E9E00ULL, +0xEC00ECEC00ECEC00ULL, 0x8000808000808000ULL, 0x2D002D2D002D2D00ULL, 0x6B006B6B006B6B00ULL, +0xA800A8A800A8A800ULL, 0x2B002B2B002B2B00ULL, 0x3600363600363600ULL, 0xA600A6A600A6A600ULL, +0xC500C5C500C5C500ULL, 0x8600868600868600ULL, 0x4D004D4D004D4D00ULL, 0x3300333300333300ULL, +0xFD00FDFD00FDFD00ULL, 0x6600666600666600ULL, 0x5800585800585800ULL, 0x9600969600969600ULL, +0x3A003A3A003A3A00ULL, 0x0900090900090900ULL, 0x9500959500959500ULL, 0x1000101000101000ULL, +0x7800787800787800ULL, 0xD800D8D800D8D800ULL, 0x4200424200424200ULL, 0xCC00CCCC00CCCC00ULL, +0xEF00EFEF00EFEF00ULL, 0x2600262600262600ULL, 0xE500E5E500E5E500ULL, 0x6100616100616100ULL, +0x1A001A1A001A1A00ULL, 0x3F003F3F003F3F00ULL, 0x3B003B3B003B3B00ULL, 0x8200828200828200ULL, +0xB600B6B600B6B600ULL, 0xDB00DBDB00DBDB00ULL, 0xD400D4D400D4D400ULL, 0x9800989800989800ULL, +0xE800E8E800E8E800ULL, 0x8B008B8B008B8B00ULL, 0x0200020200020200ULL, 0xEB00EBEB00EBEB00ULL, +0x0A000A0A000A0A00ULL, 0x2C002C2C002C2C00ULL, 0x1D001D1D001D1D00ULL, 0xB000B0B000B0B000ULL, +0x6F006F6F006F6F00ULL, 0x8D008D8D008D8D00ULL, 0x8800888800888800ULL, 0x0E000E0E000E0E00ULL, +0x1900191900191900ULL, 0x8700878700878700ULL, 0x4E004E4E004E4E00ULL, 0x0B000B0B000B0B00ULL, +0xA900A9A900A9A900ULL, 0x0C000C0C000C0C00ULL, 0x7900797900797900ULL, 0x1100111100111100ULL, +0x7F007F7F007F7F00ULL, 0x2200222200222200ULL, 0xE700E7E700E7E700ULL, 0x5900595900595900ULL, +0xE100E1E100E1E100ULL, 0xDA00DADA00DADA00ULL, 0x3D003D3D003D3D00ULL, 0xC800C8C800C8C800ULL, +0x1200121200121200ULL, 0x0400040400040400ULL, 0x7400747400747400ULL, 0x5400545400545400ULL, +0x3000303000303000ULL, 0x7E007E7E007E7E00ULL, 0xB400B4B400B4B400ULL, 0x2800282800282800ULL, +0x5500555500555500ULL, 0x6800686800686800ULL, 0x5000505000505000ULL, 0xBE00BEBE00BEBE00ULL, +0xD000D0D000D0D000ULL, 0xC400C4C400C4C400ULL, 0x3100313100313100ULL, 0xCB00CBCB00CBCB00ULL, +0x2A002A2A002A2A00ULL, 0xAD00ADAD00ADAD00ULL, 0x0F000F0F000F0F00ULL, 0xCA00CACA00CACA00ULL, +0x7000707000707000ULL, 0xFF00FFFF00FFFF00ULL, 0x3200323200323200ULL, 0x6900696900696900ULL, +0x0800080800080800ULL, 0x6200626200626200ULL, 0x0000000000000000ULL, 0x2400242400242400ULL, +0xD100D1D100D1D100ULL, 0xFB00FBFB00FBFB00ULL, 0xBA00BABA00BABA00ULL, 0xED00EDED00EDED00ULL, +0x4500454500454500ULL, 0x8100818100818100ULL, 0x7300737300737300ULL, 0x6D006D6D006D6D00ULL, +0x8400848400848400ULL, 0x9F009F9F009F9F00ULL, 0xEE00EEEE00EEEE00ULL, 0x4A004A4A004A4A00ULL, +0xC300C3C300C3C300ULL, 0x2E002E2E002E2E00ULL, 0xC100C1C100C1C100ULL, 0x0100010100010100ULL, +0xE600E6E600E6E600ULL, 0x2500252500252500ULL, 0x4800484800484800ULL, 0x9900999900999900ULL, +0xB900B9B900B9B900ULL, 0xB300B3B300B3B300ULL, 0x7B007B7B007B7B00ULL, 0xF900F9F900F9F900ULL, +0xCE00CECE00CECE00ULL, 0xBF00BFBF00BFBF00ULL, 0xDF00DFDF00DFDF00ULL, 0x7100717100717100ULL, +0x2900292900292900ULL, 0xCD00CDCD00CDCD00ULL, 0x6C006C6C006C6C00ULL, 0x1300131300131300ULL, +0x6400646400646400ULL, 0x9B009B9B009B9B00ULL, 0x6300636300636300ULL, 0x9D009D9D009D9D00ULL, +0xC000C0C000C0C000ULL, 0x4B004B4B004B4B00ULL, 0xB700B7B700B7B700ULL, 0xA500A5A500A5A500ULL, +0x8900898900898900ULL, 0x5F005F5F005F5F00ULL, 0xB100B1B100B1B100ULL, 0x1700171700171700ULL, +0xF400F4F400F4F400ULL, 0xBC00BCBC00BCBC00ULL, 0xD300D3D300D3D300ULL, 0x4600464600464600ULL, +0xCF00CFCF00CFCF00ULL, 0x3700373700373700ULL, 0x5E005E5E005E5E00ULL, 0x4700474700474700ULL, +0x9400949400949400ULL, 0xFA00FAFA00FAFA00ULL, 0xFC00FCFC00FCFC00ULL, 0x5B005B5B005B5B00ULL, +0x9700979700979700ULL, 0xFE00FEFE00FEFE00ULL, 0x5A005A5A005A5A00ULL, 0xAC00ACAC00ACAC00ULL, +0x3C003C3C003C3C00ULL, 0x4C004C4C004C4C00ULL, 0x0300030300030300ULL, 0x3500353500353500ULL, +0xF300F3F300F3F300ULL, 0x2300232300232300ULL, 0xB800B8B800B8B800ULL, 0x5D005D5D005D5D00ULL, +0x6A006A6A006A6A00ULL, 0x9200929200929200ULL, 0xD500D5D500D5D500ULL, 0x2100212100212100ULL, +0x4400444400444400ULL, 0x5100515100515100ULL, 0xC600C6C600C6C600ULL, 0x7D007D7D007D7D00ULL, +0x3900393900393900ULL, 0x8300838300838300ULL, 0xDC00DCDC00DCDC00ULL, 0xAA00AAAA00AAAA00ULL, +0x7C007C7C007C7C00ULL, 0x7700777700777700ULL, 0x5600565600565600ULL, 0x0500050500050500ULL, +0x1B001B1B001B1B00ULL, 0xA400A4A400A4A400ULL, 0x1500151500151500ULL, 0x3400343400343400ULL, +0x1E001E1E001E1E00ULL, 0x1C001C1C001C1C00ULL, 0xF800F8F800F8F800ULL, 0x5200525200525200ULL, +0x2000202000202000ULL, 0x1400141400141400ULL, 0xE900E9E900E9E900ULL, 0xBD00BDBD00BDBD00ULL, +0xDD00DDDD00DDDD00ULL, 0xE400E4E400E4E400ULL, 0xA100A1A100A1A100ULL, 0xE000E0E000E0E000ULL, +0x8A008A8A008A8A00ULL, 0xF100F1F100F1F100ULL, 0xD600D6D600D6D600ULL, 0x7A007A7A007A7A00ULL, +0xBB00BBBB00BBBB00ULL, 0xE300E3E300E3E300ULL, 0x4000404000404000ULL, 0x4F004F4F004F4F00ULL }; + +const u64bit Camellia_SBOX4[256] = { +0x7070007000007070ULL, 0x2C2C002C00002C2CULL, 0xB3B300B30000B3B3ULL, 0xC0C000C00000C0C0ULL, +0xE4E400E40000E4E4ULL, 0x5757005700005757ULL, 0xEAEA00EA0000EAEAULL, 0xAEAE00AE0000AEAEULL, +0x2323002300002323ULL, 0x6B6B006B00006B6BULL, 0x4545004500004545ULL, 0xA5A500A50000A5A5ULL, +0xEDED00ED0000EDEDULL, 0x4F4F004F00004F4FULL, 0x1D1D001D00001D1DULL, 0x9292009200009292ULL, +0x8686008600008686ULL, 0xAFAF00AF0000AFAFULL, 0x7C7C007C00007C7CULL, 0x1F1F001F00001F1FULL, +0x3E3E003E00003E3EULL, 0xDCDC00DC0000DCDCULL, 0x5E5E005E00005E5EULL, 0x0B0B000B00000B0BULL, +0xA6A600A60000A6A6ULL, 0x3939003900003939ULL, 0xD5D500D50000D5D5ULL, 0x5D5D005D00005D5DULL, +0xD9D900D90000D9D9ULL, 0x5A5A005A00005A5AULL, 0x5151005100005151ULL, 0x6C6C006C00006C6CULL, +0x8B8B008B00008B8BULL, 0x9A9A009A00009A9AULL, 0xFBFB00FB0000FBFBULL, 0xB0B000B00000B0B0ULL, +0x7474007400007474ULL, 0x2B2B002B00002B2BULL, 0xF0F000F00000F0F0ULL, 0x8484008400008484ULL, +0xDFDF00DF0000DFDFULL, 0xCBCB00CB0000CBCBULL, 0x3434003400003434ULL, 0x7676007600007676ULL, +0x6D6D006D00006D6DULL, 0xA9A900A90000A9A9ULL, 0xD1D100D10000D1D1ULL, 0x0404000400000404ULL, +0x1414001400001414ULL, 0x3A3A003A00003A3AULL, 0xDEDE00DE0000DEDEULL, 0x1111001100001111ULL, +0x3232003200003232ULL, 0x9C9C009C00009C9CULL, 0x5353005300005353ULL, 0xF2F200F20000F2F2ULL, +0xFEFE00FE0000FEFEULL, 0xCFCF00CF0000CFCFULL, 0xC3C300C30000C3C3ULL, 0x7A7A007A00007A7AULL, +0x2424002400002424ULL, 0xE8E800E80000E8E8ULL, 0x6060006000006060ULL, 0x6969006900006969ULL, +0xAAAA00AA0000AAAAULL, 0xA0A000A00000A0A0ULL, 0xA1A100A10000A1A1ULL, 0x6262006200006262ULL, +0x5454005400005454ULL, 0x1E1E001E00001E1EULL, 0xE0E000E00000E0E0ULL, 0x6464006400006464ULL, +0x1010001000001010ULL, 0x0000000000000000ULL, 0xA3A300A30000A3A3ULL, 0x7575007500007575ULL, +0x8A8A008A00008A8AULL, 0xE6E600E60000E6E6ULL, 0x0909000900000909ULL, 0xDDDD00DD0000DDDDULL, +0x8787008700008787ULL, 0x8383008300008383ULL, 0xCDCD00CD0000CDCDULL, 0x9090009000009090ULL, +0x7373007300007373ULL, 0xF6F600F60000F6F6ULL, 0x9D9D009D00009D9DULL, 0xBFBF00BF0000BFBFULL, +0x5252005200005252ULL, 0xD8D800D80000D8D8ULL, 0xC8C800C80000C8C8ULL, 0xC6C600C60000C6C6ULL, +0x8181008100008181ULL, 0x6F6F006F00006F6FULL, 0x1313001300001313ULL, 0x6363006300006363ULL, +0xE9E900E90000E9E9ULL, 0xA7A700A70000A7A7ULL, 0x9F9F009F00009F9FULL, 0xBCBC00BC0000BCBCULL, +0x2929002900002929ULL, 0xF9F900F90000F9F9ULL, 0x2F2F002F00002F2FULL, 0xB4B400B40000B4B4ULL, +0x7878007800007878ULL, 0x0606000600000606ULL, 0xE7E700E70000E7E7ULL, 0x7171007100007171ULL, +0xD4D400D40000D4D4ULL, 0xABAB00AB0000ABABULL, 0x8888008800008888ULL, 0x8D8D008D00008D8DULL, +0x7272007200007272ULL, 0xB9B900B90000B9B9ULL, 0xF8F800F80000F8F8ULL, 0xACAC00AC0000ACACULL, +0x3636003600003636ULL, 0x2A2A002A00002A2AULL, 0x3C3C003C00003C3CULL, 0xF1F100F10000F1F1ULL, +0x4040004000004040ULL, 0xD3D300D30000D3D3ULL, 0xBBBB00BB0000BBBBULL, 0x4343004300004343ULL, +0x1515001500001515ULL, 0xADAD00AD0000ADADULL, 0x7777007700007777ULL, 0x8080008000008080ULL, +0x8282008200008282ULL, 0xECEC00EC0000ECECULL, 0x2727002700002727ULL, 0xE5E500E50000E5E5ULL, +0x8585008500008585ULL, 0x3535003500003535ULL, 0x0C0C000C00000C0CULL, 0x4141004100004141ULL, +0xEFEF00EF0000EFEFULL, 0x9393009300009393ULL, 0x1919001900001919ULL, 0x2121002100002121ULL, +0x0E0E000E00000E0EULL, 0x4E4E004E00004E4EULL, 0x6565006500006565ULL, 0xBDBD00BD0000BDBDULL, +0xB8B800B80000B8B8ULL, 0x8F8F008F00008F8FULL, 0xEBEB00EB0000EBEBULL, 0xCECE00CE0000CECEULL, +0x3030003000003030ULL, 0x5F5F005F00005F5FULL, 0xC5C500C50000C5C5ULL, 0x1A1A001A00001A1AULL, +0xE1E100E10000E1E1ULL, 0xCACA00CA0000CACAULL, 0x4747004700004747ULL, 0x3D3D003D00003D3DULL, +0x0101000100000101ULL, 0xD6D600D60000D6D6ULL, 0x5656005600005656ULL, 0x4D4D004D00004D4DULL, +0x0D0D000D00000D0DULL, 0x6666006600006666ULL, 0xCCCC00CC0000CCCCULL, 0x2D2D002D00002D2DULL, +0x1212001200001212ULL, 0x2020002000002020ULL, 0xB1B100B10000B1B1ULL, 0x9999009900009999ULL, +0x4C4C004C00004C4CULL, 0xC2C200C20000C2C2ULL, 0x7E7E007E00007E7EULL, 0x0505000500000505ULL, +0xB7B700B70000B7B7ULL, 0x3131003100003131ULL, 0x1717001700001717ULL, 0xD7D700D70000D7D7ULL, +0x5858005800005858ULL, 0x6161006100006161ULL, 0x1B1B001B00001B1BULL, 0x1C1C001C00001C1CULL, +0x0F0F000F00000F0FULL, 0x1616001600001616ULL, 0x1818001800001818ULL, 0x2222002200002222ULL, +0x4444004400004444ULL, 0xB2B200B20000B2B2ULL, 0xB5B500B50000B5B5ULL, 0x9191009100009191ULL, +0x0808000800000808ULL, 0xA8A800A80000A8A8ULL, 0xFCFC00FC0000FCFCULL, 0x5050005000005050ULL, +0xD0D000D00000D0D0ULL, 0x7D7D007D00007D7DULL, 0x8989008900008989ULL, 0x9797009700009797ULL, +0x5B5B005B00005B5BULL, 0x9595009500009595ULL, 0xFFFF00FF0000FFFFULL, 0xD2D200D20000D2D2ULL, +0xC4C400C40000C4C4ULL, 0x4848004800004848ULL, 0xF7F700F70000F7F7ULL, 0xDBDB00DB0000DBDBULL, +0x0303000300000303ULL, 0xDADA00DA0000DADAULL, 0x3F3F003F00003F3FULL, 0x9494009400009494ULL, +0x5C5C005C00005C5CULL, 0x0202000200000202ULL, 0x4A4A004A00004A4AULL, 0x3333003300003333ULL, +0x6767006700006767ULL, 0xF3F300F30000F3F3ULL, 0x7F7F007F00007F7FULL, 0xE2E200E20000E2E2ULL, +0x9B9B009B00009B9BULL, 0x2626002600002626ULL, 0x3737003700003737ULL, 0x3B3B003B00003B3BULL, +0x9696009600009696ULL, 0x4B4B004B00004B4BULL, 0xBEBE00BE0000BEBEULL, 0x2E2E002E00002E2EULL, +0x7979007900007979ULL, 0x8C8C008C00008C8CULL, 0x6E6E006E00006E6EULL, 0x8E8E008E00008E8EULL, +0xF5F500F50000F5F5ULL, 0xB6B600B60000B6B6ULL, 0xFDFD00FD0000FDFDULL, 0x5959005900005959ULL, +0x9898009800009898ULL, 0x6A6A006A00006A6AULL, 0x4646004600004646ULL, 0xBABA00BA0000BABAULL, +0x2525002500002525ULL, 0x4242004200004242ULL, 0xA2A200A20000A2A2ULL, 0xFAFA00FA0000FAFAULL, +0x0707000700000707ULL, 0x5555005500005555ULL, 0xEEEE00EE0000EEEEULL, 0x0A0A000A00000A0AULL, +0x4949004900004949ULL, 0x6868006800006868ULL, 0x3838003800003838ULL, 0xA4A400A40000A4A4ULL, +0x2828002800002828ULL, 0x7B7B007B00007B7BULL, 0xC9C900C90000C9C9ULL, 0xC1C100C10000C1C1ULL, +0xE3E300E30000E3E3ULL, 0xF4F400F40000F4F4ULL, 0xC7C700C70000C7C7ULL, 0x9E9E009E00009E9EULL }; + +const u64bit Camellia_SBOX5[256] = { +0x00E0E0E000E0E0E0ULL, 0x0005050500050505ULL, 0x0058585800585858ULL, 0x00D9D9D900D9D9D9ULL, +0x0067676700676767ULL, 0x004E4E4E004E4E4EULL, 0x0081818100818181ULL, 0x00CBCBCB00CBCBCBULL, +0x00C9C9C900C9C9C9ULL, 0x000B0B0B000B0B0BULL, 0x00AEAEAE00AEAEAEULL, 0x006A6A6A006A6A6AULL, +0x00D5D5D500D5D5D5ULL, 0x0018181800181818ULL, 0x005D5D5D005D5D5DULL, 0x0082828200828282ULL, +0x0046464600464646ULL, 0x00DFDFDF00DFDFDFULL, 0x00D6D6D600D6D6D6ULL, 0x0027272700272727ULL, +0x008A8A8A008A8A8AULL, 0x0032323200323232ULL, 0x004B4B4B004B4B4BULL, 0x0042424200424242ULL, +0x00DBDBDB00DBDBDBULL, 0x001C1C1C001C1C1CULL, 0x009E9E9E009E9E9EULL, 0x009C9C9C009C9C9CULL, +0x003A3A3A003A3A3AULL, 0x00CACACA00CACACAULL, 0x0025252500252525ULL, 0x007B7B7B007B7B7BULL, +0x000D0D0D000D0D0DULL, 0x0071717100717171ULL, 0x005F5F5F005F5F5FULL, 0x001F1F1F001F1F1FULL, +0x00F8F8F800F8F8F8ULL, 0x00D7D7D700D7D7D7ULL, 0x003E3E3E003E3E3EULL, 0x009D9D9D009D9D9DULL, +0x007C7C7C007C7C7CULL, 0x0060606000606060ULL, 0x00B9B9B900B9B9B9ULL, 0x00BEBEBE00BEBEBEULL, +0x00BCBCBC00BCBCBCULL, 0x008B8B8B008B8B8BULL, 0x0016161600161616ULL, 0x0034343400343434ULL, +0x004D4D4D004D4D4DULL, 0x00C3C3C300C3C3C3ULL, 0x0072727200727272ULL, 0x0095959500959595ULL, +0x00ABABAB00ABABABULL, 0x008E8E8E008E8E8EULL, 0x00BABABA00BABABAULL, 0x007A7A7A007A7A7AULL, +0x00B3B3B300B3B3B3ULL, 0x0002020200020202ULL, 0x00B4B4B400B4B4B4ULL, 0x00ADADAD00ADADADULL, +0x00A2A2A200A2A2A2ULL, 0x00ACACAC00ACACACULL, 0x00D8D8D800D8D8D8ULL, 0x009A9A9A009A9A9AULL, +0x0017171700171717ULL, 0x001A1A1A001A1A1AULL, 0x0035353500353535ULL, 0x00CCCCCC00CCCCCCULL, +0x00F7F7F700F7F7F7ULL, 0x0099999900999999ULL, 0x0061616100616161ULL, 0x005A5A5A005A5A5AULL, +0x00E8E8E800E8E8E8ULL, 0x0024242400242424ULL, 0x0056565600565656ULL, 0x0040404000404040ULL, +0x00E1E1E100E1E1E1ULL, 0x0063636300636363ULL, 0x0009090900090909ULL, 0x0033333300333333ULL, +0x00BFBFBF00BFBFBFULL, 0x0098989800989898ULL, 0x0097979700979797ULL, 0x0085858500858585ULL, +0x0068686800686868ULL, 0x00FCFCFC00FCFCFCULL, 0x00ECECEC00ECECECULL, 0x000A0A0A000A0A0AULL, +0x00DADADA00DADADAULL, 0x006F6F6F006F6F6FULL, 0x0053535300535353ULL, 0x0062626200626262ULL, +0x00A3A3A300A3A3A3ULL, 0x002E2E2E002E2E2EULL, 0x0008080800080808ULL, 0x00AFAFAF00AFAFAFULL, +0x0028282800282828ULL, 0x00B0B0B000B0B0B0ULL, 0x0074747400747474ULL, 0x00C2C2C200C2C2C2ULL, +0x00BDBDBD00BDBDBDULL, 0x0036363600363636ULL, 0x0022222200222222ULL, 0x0038383800383838ULL, +0x0064646400646464ULL, 0x001E1E1E001E1E1EULL, 0x0039393900393939ULL, 0x002C2C2C002C2C2CULL, +0x00A6A6A600A6A6A6ULL, 0x0030303000303030ULL, 0x00E5E5E500E5E5E5ULL, 0x0044444400444444ULL, +0x00FDFDFD00FDFDFDULL, 0x0088888800888888ULL, 0x009F9F9F009F9F9FULL, 0x0065656500656565ULL, +0x0087878700878787ULL, 0x006B6B6B006B6B6BULL, 0x00F4F4F400F4F4F4ULL, 0x0023232300232323ULL, +0x0048484800484848ULL, 0x0010101000101010ULL, 0x00D1D1D100D1D1D1ULL, 0x0051515100515151ULL, +0x00C0C0C000C0C0C0ULL, 0x00F9F9F900F9F9F9ULL, 0x00D2D2D200D2D2D2ULL, 0x00A0A0A000A0A0A0ULL, +0x0055555500555555ULL, 0x00A1A1A100A1A1A1ULL, 0x0041414100414141ULL, 0x00FAFAFA00FAFAFAULL, +0x0043434300434343ULL, 0x0013131300131313ULL, 0x00C4C4C400C4C4C4ULL, 0x002F2F2F002F2F2FULL, +0x00A8A8A800A8A8A8ULL, 0x00B6B6B600B6B6B6ULL, 0x003C3C3C003C3C3CULL, 0x002B2B2B002B2B2BULL, +0x00C1C1C100C1C1C1ULL, 0x00FFFFFF00FFFFFFULL, 0x00C8C8C800C8C8C8ULL, 0x00A5A5A500A5A5A5ULL, +0x0020202000202020ULL, 0x0089898900898989ULL, 0x0000000000000000ULL, 0x0090909000909090ULL, +0x0047474700474747ULL, 0x00EFEFEF00EFEFEFULL, 0x00EAEAEA00EAEAEAULL, 0x00B7B7B700B7B7B7ULL, +0x0015151500151515ULL, 0x0006060600060606ULL, 0x00CDCDCD00CDCDCDULL, 0x00B5B5B500B5B5B5ULL, +0x0012121200121212ULL, 0x007E7E7E007E7E7EULL, 0x00BBBBBB00BBBBBBULL, 0x0029292900292929ULL, +0x000F0F0F000F0F0FULL, 0x00B8B8B800B8B8B8ULL, 0x0007070700070707ULL, 0x0004040400040404ULL, +0x009B9B9B009B9B9BULL, 0x0094949400949494ULL, 0x0021212100212121ULL, 0x0066666600666666ULL, +0x00E6E6E600E6E6E6ULL, 0x00CECECE00CECECEULL, 0x00EDEDED00EDEDEDULL, 0x00E7E7E700E7E7E7ULL, +0x003B3B3B003B3B3BULL, 0x00FEFEFE00FEFEFEULL, 0x007F7F7F007F7F7FULL, 0x00C5C5C500C5C5C5ULL, +0x00A4A4A400A4A4A4ULL, 0x0037373700373737ULL, 0x00B1B1B100B1B1B1ULL, 0x004C4C4C004C4C4CULL, +0x0091919100919191ULL, 0x006E6E6E006E6E6EULL, 0x008D8D8D008D8D8DULL, 0x0076767600767676ULL, +0x0003030300030303ULL, 0x002D2D2D002D2D2DULL, 0x00DEDEDE00DEDEDEULL, 0x0096969600969696ULL, +0x0026262600262626ULL, 0x007D7D7D007D7D7DULL, 0x00C6C6C600C6C6C6ULL, 0x005C5C5C005C5C5CULL, +0x00D3D3D300D3D3D3ULL, 0x00F2F2F200F2F2F2ULL, 0x004F4F4F004F4F4FULL, 0x0019191900191919ULL, +0x003F3F3F003F3F3FULL, 0x00DCDCDC00DCDCDCULL, 0x0079797900797979ULL, 0x001D1D1D001D1D1DULL, +0x0052525200525252ULL, 0x00EBEBEB00EBEBEBULL, 0x00F3F3F300F3F3F3ULL, 0x006D6D6D006D6D6DULL, +0x005E5E5E005E5E5EULL, 0x00FBFBFB00FBFBFBULL, 0x0069696900696969ULL, 0x00B2B2B200B2B2B2ULL, +0x00F0F0F000F0F0F0ULL, 0x0031313100313131ULL, 0x000C0C0C000C0C0CULL, 0x00D4D4D400D4D4D4ULL, +0x00CFCFCF00CFCFCFULL, 0x008C8C8C008C8C8CULL, 0x00E2E2E200E2E2E2ULL, 0x0075757500757575ULL, +0x00A9A9A900A9A9A9ULL, 0x004A4A4A004A4A4AULL, 0x0057575700575757ULL, 0x0084848400848484ULL, +0x0011111100111111ULL, 0x0045454500454545ULL, 0x001B1B1B001B1B1BULL, 0x00F5F5F500F5F5F5ULL, +0x00E4E4E400E4E4E4ULL, 0x000E0E0E000E0E0EULL, 0x0073737300737373ULL, 0x00AAAAAA00AAAAAAULL, +0x00F1F1F100F1F1F1ULL, 0x00DDDDDD00DDDDDDULL, 0x0059595900595959ULL, 0x0014141400141414ULL, +0x006C6C6C006C6C6CULL, 0x0092929200929292ULL, 0x0054545400545454ULL, 0x00D0D0D000D0D0D0ULL, +0x0078787800787878ULL, 0x0070707000707070ULL, 0x00E3E3E300E3E3E3ULL, 0x0049494900494949ULL, +0x0080808000808080ULL, 0x0050505000505050ULL, 0x00A7A7A700A7A7A7ULL, 0x00F6F6F600F6F6F6ULL, +0x0077777700777777ULL, 0x0093939300939393ULL, 0x0086868600868686ULL, 0x0083838300838383ULL, +0x002A2A2A002A2A2AULL, 0x00C7C7C700C7C7C7ULL, 0x005B5B5B005B5B5BULL, 0x00E9E9E900E9E9E9ULL, +0x00EEEEEE00EEEEEEULL, 0x008F8F8F008F8F8FULL, 0x0001010100010101ULL, 0x003D3D3D003D3D3DULL }; + +const u64bit Camellia_SBOX6[256] = { +0x3800383838003838ULL, 0x4100414141004141ULL, 0x1600161616001616ULL, 0x7600767676007676ULL, +0xD900D9D9D900D9D9ULL, 0x9300939393009393ULL, 0x6000606060006060ULL, 0xF200F2F2F200F2F2ULL, +0x7200727272007272ULL, 0xC200C2C2C200C2C2ULL, 0xAB00ABABAB00ABABULL, 0x9A009A9A9A009A9AULL, +0x7500757575007575ULL, 0x0600060606000606ULL, 0x5700575757005757ULL, 0xA000A0A0A000A0A0ULL, +0x9100919191009191ULL, 0xF700F7F7F700F7F7ULL, 0xB500B5B5B500B5B5ULL, 0xC900C9C9C900C9C9ULL, +0xA200A2A2A200A2A2ULL, 0x8C008C8C8C008C8CULL, 0xD200D2D2D200D2D2ULL, 0x9000909090009090ULL, +0xF600F6F6F600F6F6ULL, 0x0700070707000707ULL, 0xA700A7A7A700A7A7ULL, 0x2700272727002727ULL, +0x8E008E8E8E008E8EULL, 0xB200B2B2B200B2B2ULL, 0x4900494949004949ULL, 0xDE00DEDEDE00DEDEULL, +0x4300434343004343ULL, 0x5C005C5C5C005C5CULL, 0xD700D7D7D700D7D7ULL, 0xC700C7C7C700C7C7ULL, +0x3E003E3E3E003E3EULL, 0xF500F5F5F500F5F5ULL, 0x8F008F8F8F008F8FULL, 0x6700676767006767ULL, +0x1F001F1F1F001F1FULL, 0x1800181818001818ULL, 0x6E006E6E6E006E6EULL, 0xAF00AFAFAF00AFAFULL, +0x2F002F2F2F002F2FULL, 0xE200E2E2E200E2E2ULL, 0x8500858585008585ULL, 0x0D000D0D0D000D0DULL, +0x5300535353005353ULL, 0xF000F0F0F000F0F0ULL, 0x9C009C9C9C009C9CULL, 0x6500656565006565ULL, +0xEA00EAEAEA00EAEAULL, 0xA300A3A3A300A3A3ULL, 0xAE00AEAEAE00AEAEULL, 0x9E009E9E9E009E9EULL, +0xEC00ECECEC00ECECULL, 0x8000808080008080ULL, 0x2D002D2D2D002D2DULL, 0x6B006B6B6B006B6BULL, +0xA800A8A8A800A8A8ULL, 0x2B002B2B2B002B2BULL, 0x3600363636003636ULL, 0xA600A6A6A600A6A6ULL, +0xC500C5C5C500C5C5ULL, 0x8600868686008686ULL, 0x4D004D4D4D004D4DULL, 0x3300333333003333ULL, +0xFD00FDFDFD00FDFDULL, 0x6600666666006666ULL, 0x5800585858005858ULL, 0x9600969696009696ULL, +0x3A003A3A3A003A3AULL, 0x0900090909000909ULL, 0x9500959595009595ULL, 0x1000101010001010ULL, +0x7800787878007878ULL, 0xD800D8D8D800D8D8ULL, 0x4200424242004242ULL, 0xCC00CCCCCC00CCCCULL, +0xEF00EFEFEF00EFEFULL, 0x2600262626002626ULL, 0xE500E5E5E500E5E5ULL, 0x6100616161006161ULL, +0x1A001A1A1A001A1AULL, 0x3F003F3F3F003F3FULL, 0x3B003B3B3B003B3BULL, 0x8200828282008282ULL, +0xB600B6B6B600B6B6ULL, 0xDB00DBDBDB00DBDBULL, 0xD400D4D4D400D4D4ULL, 0x9800989898009898ULL, +0xE800E8E8E800E8E8ULL, 0x8B008B8B8B008B8BULL, 0x0200020202000202ULL, 0xEB00EBEBEB00EBEBULL, +0x0A000A0A0A000A0AULL, 0x2C002C2C2C002C2CULL, 0x1D001D1D1D001D1DULL, 0xB000B0B0B000B0B0ULL, +0x6F006F6F6F006F6FULL, 0x8D008D8D8D008D8DULL, 0x8800888888008888ULL, 0x0E000E0E0E000E0EULL, +0x1900191919001919ULL, 0x8700878787008787ULL, 0x4E004E4E4E004E4EULL, 0x0B000B0B0B000B0BULL, +0xA900A9A9A900A9A9ULL, 0x0C000C0C0C000C0CULL, 0x7900797979007979ULL, 0x1100111111001111ULL, +0x7F007F7F7F007F7FULL, 0x2200222222002222ULL, 0xE700E7E7E700E7E7ULL, 0x5900595959005959ULL, +0xE100E1E1E100E1E1ULL, 0xDA00DADADA00DADAULL, 0x3D003D3D3D003D3DULL, 0xC800C8C8C800C8C8ULL, +0x1200121212001212ULL, 0x0400040404000404ULL, 0x7400747474007474ULL, 0x5400545454005454ULL, +0x3000303030003030ULL, 0x7E007E7E7E007E7EULL, 0xB400B4B4B400B4B4ULL, 0x2800282828002828ULL, +0x5500555555005555ULL, 0x6800686868006868ULL, 0x5000505050005050ULL, 0xBE00BEBEBE00BEBEULL, +0xD000D0D0D000D0D0ULL, 0xC400C4C4C400C4C4ULL, 0x3100313131003131ULL, 0xCB00CBCBCB00CBCBULL, +0x2A002A2A2A002A2AULL, 0xAD00ADADAD00ADADULL, 0x0F000F0F0F000F0FULL, 0xCA00CACACA00CACAULL, +0x7000707070007070ULL, 0xFF00FFFFFF00FFFFULL, 0x3200323232003232ULL, 0x6900696969006969ULL, +0x0800080808000808ULL, 0x6200626262006262ULL, 0x0000000000000000ULL, 0x2400242424002424ULL, +0xD100D1D1D100D1D1ULL, 0xFB00FBFBFB00FBFBULL, 0xBA00BABABA00BABAULL, 0xED00EDEDED00EDEDULL, +0x4500454545004545ULL, 0x8100818181008181ULL, 0x7300737373007373ULL, 0x6D006D6D6D006D6DULL, +0x8400848484008484ULL, 0x9F009F9F9F009F9FULL, 0xEE00EEEEEE00EEEEULL, 0x4A004A4A4A004A4AULL, +0xC300C3C3C300C3C3ULL, 0x2E002E2E2E002E2EULL, 0xC100C1C1C100C1C1ULL, 0x0100010101000101ULL, +0xE600E6E6E600E6E6ULL, 0x2500252525002525ULL, 0x4800484848004848ULL, 0x9900999999009999ULL, +0xB900B9B9B900B9B9ULL, 0xB300B3B3B300B3B3ULL, 0x7B007B7B7B007B7BULL, 0xF900F9F9F900F9F9ULL, +0xCE00CECECE00CECEULL, 0xBF00BFBFBF00BFBFULL, 0xDF00DFDFDF00DFDFULL, 0x7100717171007171ULL, +0x2900292929002929ULL, 0xCD00CDCDCD00CDCDULL, 0x6C006C6C6C006C6CULL, 0x1300131313001313ULL, +0x6400646464006464ULL, 0x9B009B9B9B009B9BULL, 0x6300636363006363ULL, 0x9D009D9D9D009D9DULL, +0xC000C0C0C000C0C0ULL, 0x4B004B4B4B004B4BULL, 0xB700B7B7B700B7B7ULL, 0xA500A5A5A500A5A5ULL, +0x8900898989008989ULL, 0x5F005F5F5F005F5FULL, 0xB100B1B1B100B1B1ULL, 0x1700171717001717ULL, +0xF400F4F4F400F4F4ULL, 0xBC00BCBCBC00BCBCULL, 0xD300D3D3D300D3D3ULL, 0x4600464646004646ULL, +0xCF00CFCFCF00CFCFULL, 0x3700373737003737ULL, 0x5E005E5E5E005E5EULL, 0x4700474747004747ULL, +0x9400949494009494ULL, 0xFA00FAFAFA00FAFAULL, 0xFC00FCFCFC00FCFCULL, 0x5B005B5B5B005B5BULL, +0x9700979797009797ULL, 0xFE00FEFEFE00FEFEULL, 0x5A005A5A5A005A5AULL, 0xAC00ACACAC00ACACULL, +0x3C003C3C3C003C3CULL, 0x4C004C4C4C004C4CULL, 0x0300030303000303ULL, 0x3500353535003535ULL, +0xF300F3F3F300F3F3ULL, 0x2300232323002323ULL, 0xB800B8B8B800B8B8ULL, 0x5D005D5D5D005D5DULL, +0x6A006A6A6A006A6AULL, 0x9200929292009292ULL, 0xD500D5D5D500D5D5ULL, 0x2100212121002121ULL, +0x4400444444004444ULL, 0x5100515151005151ULL, 0xC600C6C6C600C6C6ULL, 0x7D007D7D7D007D7DULL, +0x3900393939003939ULL, 0x8300838383008383ULL, 0xDC00DCDCDC00DCDCULL, 0xAA00AAAAAA00AAAAULL, +0x7C007C7C7C007C7CULL, 0x7700777777007777ULL, 0x5600565656005656ULL, 0x0500050505000505ULL, +0x1B001B1B1B001B1BULL, 0xA400A4A4A400A4A4ULL, 0x1500151515001515ULL, 0x3400343434003434ULL, +0x1E001E1E1E001E1EULL, 0x1C001C1C1C001C1CULL, 0xF800F8F8F800F8F8ULL, 0x5200525252005252ULL, +0x2000202020002020ULL, 0x1400141414001414ULL, 0xE900E9E9E900E9E9ULL, 0xBD00BDBDBD00BDBDULL, +0xDD00DDDDDD00DDDDULL, 0xE400E4E4E400E4E4ULL, 0xA100A1A1A100A1A1ULL, 0xE000E0E0E000E0E0ULL, +0x8A008A8A8A008A8AULL, 0xF100F1F1F100F1F1ULL, 0xD600D6D6D600D6D6ULL, 0x7A007A7A7A007A7AULL, +0xBB00BBBBBB00BBBBULL, 0xE300E3E3E300E3E3ULL, 0x4000404040004040ULL, 0x4F004F4F4F004F4FULL }; + +const u64bit Camellia_SBOX7[256] = { +0x7070007070700070ULL, 0x2C2C002C2C2C002CULL, 0xB3B300B3B3B300B3ULL, 0xC0C000C0C0C000C0ULL, +0xE4E400E4E4E400E4ULL, 0x5757005757570057ULL, 0xEAEA00EAEAEA00EAULL, 0xAEAE00AEAEAE00AEULL, +0x2323002323230023ULL, 0x6B6B006B6B6B006BULL, 0x4545004545450045ULL, 0xA5A500A5A5A500A5ULL, +0xEDED00EDEDED00EDULL, 0x4F4F004F4F4F004FULL, 0x1D1D001D1D1D001DULL, 0x9292009292920092ULL, +0x8686008686860086ULL, 0xAFAF00AFAFAF00AFULL, 0x7C7C007C7C7C007CULL, 0x1F1F001F1F1F001FULL, +0x3E3E003E3E3E003EULL, 0xDCDC00DCDCDC00DCULL, 0x5E5E005E5E5E005EULL, 0x0B0B000B0B0B000BULL, +0xA6A600A6A6A600A6ULL, 0x3939003939390039ULL, 0xD5D500D5D5D500D5ULL, 0x5D5D005D5D5D005DULL, +0xD9D900D9D9D900D9ULL, 0x5A5A005A5A5A005AULL, 0x5151005151510051ULL, 0x6C6C006C6C6C006CULL, +0x8B8B008B8B8B008BULL, 0x9A9A009A9A9A009AULL, 0xFBFB00FBFBFB00FBULL, 0xB0B000B0B0B000B0ULL, +0x7474007474740074ULL, 0x2B2B002B2B2B002BULL, 0xF0F000F0F0F000F0ULL, 0x8484008484840084ULL, +0xDFDF00DFDFDF00DFULL, 0xCBCB00CBCBCB00CBULL, 0x3434003434340034ULL, 0x7676007676760076ULL, +0x6D6D006D6D6D006DULL, 0xA9A900A9A9A900A9ULL, 0xD1D100D1D1D100D1ULL, 0x0404000404040004ULL, +0x1414001414140014ULL, 0x3A3A003A3A3A003AULL, 0xDEDE00DEDEDE00DEULL, 0x1111001111110011ULL, +0x3232003232320032ULL, 0x9C9C009C9C9C009CULL, 0x5353005353530053ULL, 0xF2F200F2F2F200F2ULL, +0xFEFE00FEFEFE00FEULL, 0xCFCF00CFCFCF00CFULL, 0xC3C300C3C3C300C3ULL, 0x7A7A007A7A7A007AULL, +0x2424002424240024ULL, 0xE8E800E8E8E800E8ULL, 0x6060006060600060ULL, 0x6969006969690069ULL, +0xAAAA00AAAAAA00AAULL, 0xA0A000A0A0A000A0ULL, 0xA1A100A1A1A100A1ULL, 0x6262006262620062ULL, +0x5454005454540054ULL, 0x1E1E001E1E1E001EULL, 0xE0E000E0E0E000E0ULL, 0x6464006464640064ULL, +0x1010001010100010ULL, 0x0000000000000000ULL, 0xA3A300A3A3A300A3ULL, 0x7575007575750075ULL, +0x8A8A008A8A8A008AULL, 0xE6E600E6E6E600E6ULL, 0x0909000909090009ULL, 0xDDDD00DDDDDD00DDULL, +0x8787008787870087ULL, 0x8383008383830083ULL, 0xCDCD00CDCDCD00CDULL, 0x9090009090900090ULL, +0x7373007373730073ULL, 0xF6F600F6F6F600F6ULL, 0x9D9D009D9D9D009DULL, 0xBFBF00BFBFBF00BFULL, +0x5252005252520052ULL, 0xD8D800D8D8D800D8ULL, 0xC8C800C8C8C800C8ULL, 0xC6C600C6C6C600C6ULL, +0x8181008181810081ULL, 0x6F6F006F6F6F006FULL, 0x1313001313130013ULL, 0x6363006363630063ULL, +0xE9E900E9E9E900E9ULL, 0xA7A700A7A7A700A7ULL, 0x9F9F009F9F9F009FULL, 0xBCBC00BCBCBC00BCULL, +0x2929002929290029ULL, 0xF9F900F9F9F900F9ULL, 0x2F2F002F2F2F002FULL, 0xB4B400B4B4B400B4ULL, +0x7878007878780078ULL, 0x0606000606060006ULL, 0xE7E700E7E7E700E7ULL, 0x7171007171710071ULL, +0xD4D400D4D4D400D4ULL, 0xABAB00ABABAB00ABULL, 0x8888008888880088ULL, 0x8D8D008D8D8D008DULL, +0x7272007272720072ULL, 0xB9B900B9B9B900B9ULL, 0xF8F800F8F8F800F8ULL, 0xACAC00ACACAC00ACULL, +0x3636003636360036ULL, 0x2A2A002A2A2A002AULL, 0x3C3C003C3C3C003CULL, 0xF1F100F1F1F100F1ULL, +0x4040004040400040ULL, 0xD3D300D3D3D300D3ULL, 0xBBBB00BBBBBB00BBULL, 0x4343004343430043ULL, +0x1515001515150015ULL, 0xADAD00ADADAD00ADULL, 0x7777007777770077ULL, 0x8080008080800080ULL, +0x8282008282820082ULL, 0xECEC00ECECEC00ECULL, 0x2727002727270027ULL, 0xE5E500E5E5E500E5ULL, +0x8585008585850085ULL, 0x3535003535350035ULL, 0x0C0C000C0C0C000CULL, 0x4141004141410041ULL, +0xEFEF00EFEFEF00EFULL, 0x9393009393930093ULL, 0x1919001919190019ULL, 0x2121002121210021ULL, +0x0E0E000E0E0E000EULL, 0x4E4E004E4E4E004EULL, 0x6565006565650065ULL, 0xBDBD00BDBDBD00BDULL, +0xB8B800B8B8B800B8ULL, 0x8F8F008F8F8F008FULL, 0xEBEB00EBEBEB00EBULL, 0xCECE00CECECE00CEULL, +0x3030003030300030ULL, 0x5F5F005F5F5F005FULL, 0xC5C500C5C5C500C5ULL, 0x1A1A001A1A1A001AULL, +0xE1E100E1E1E100E1ULL, 0xCACA00CACACA00CAULL, 0x4747004747470047ULL, 0x3D3D003D3D3D003DULL, +0x0101000101010001ULL, 0xD6D600D6D6D600D6ULL, 0x5656005656560056ULL, 0x4D4D004D4D4D004DULL, +0x0D0D000D0D0D000DULL, 0x6666006666660066ULL, 0xCCCC00CCCCCC00CCULL, 0x2D2D002D2D2D002DULL, +0x1212001212120012ULL, 0x2020002020200020ULL, 0xB1B100B1B1B100B1ULL, 0x9999009999990099ULL, +0x4C4C004C4C4C004CULL, 0xC2C200C2C2C200C2ULL, 0x7E7E007E7E7E007EULL, 0x0505000505050005ULL, +0xB7B700B7B7B700B7ULL, 0x3131003131310031ULL, 0x1717001717170017ULL, 0xD7D700D7D7D700D7ULL, +0x5858005858580058ULL, 0x6161006161610061ULL, 0x1B1B001B1B1B001BULL, 0x1C1C001C1C1C001CULL, +0x0F0F000F0F0F000FULL, 0x1616001616160016ULL, 0x1818001818180018ULL, 0x2222002222220022ULL, +0x4444004444440044ULL, 0xB2B200B2B2B200B2ULL, 0xB5B500B5B5B500B5ULL, 0x9191009191910091ULL, +0x0808000808080008ULL, 0xA8A800A8A8A800A8ULL, 0xFCFC00FCFCFC00FCULL, 0x5050005050500050ULL, +0xD0D000D0D0D000D0ULL, 0x7D7D007D7D7D007DULL, 0x8989008989890089ULL, 0x9797009797970097ULL, +0x5B5B005B5B5B005BULL, 0x9595009595950095ULL, 0xFFFF00FFFFFF00FFULL, 0xD2D200D2D2D200D2ULL, +0xC4C400C4C4C400C4ULL, 0x4848004848480048ULL, 0xF7F700F7F7F700F7ULL, 0xDBDB00DBDBDB00DBULL, +0x0303000303030003ULL, 0xDADA00DADADA00DAULL, 0x3F3F003F3F3F003FULL, 0x9494009494940094ULL, +0x5C5C005C5C5C005CULL, 0x0202000202020002ULL, 0x4A4A004A4A4A004AULL, 0x3333003333330033ULL, +0x6767006767670067ULL, 0xF3F300F3F3F300F3ULL, 0x7F7F007F7F7F007FULL, 0xE2E200E2E2E200E2ULL, +0x9B9B009B9B9B009BULL, 0x2626002626260026ULL, 0x3737003737370037ULL, 0x3B3B003B3B3B003BULL, +0x9696009696960096ULL, 0x4B4B004B4B4B004BULL, 0xBEBE00BEBEBE00BEULL, 0x2E2E002E2E2E002EULL, +0x7979007979790079ULL, 0x8C8C008C8C8C008CULL, 0x6E6E006E6E6E006EULL, 0x8E8E008E8E8E008EULL, +0xF5F500F5F5F500F5ULL, 0xB6B600B6B6B600B6ULL, 0xFDFD00FDFDFD00FDULL, 0x5959005959590059ULL, +0x9898009898980098ULL, 0x6A6A006A6A6A006AULL, 0x4646004646460046ULL, 0xBABA00BABABA00BAULL, +0x2525002525250025ULL, 0x4242004242420042ULL, 0xA2A200A2A2A200A2ULL, 0xFAFA00FAFAFA00FAULL, +0x0707000707070007ULL, 0x5555005555550055ULL, 0xEEEE00EEEEEE00EEULL, 0x0A0A000A0A0A000AULL, +0x4949004949490049ULL, 0x6868006868680068ULL, 0x3838003838380038ULL, 0xA4A400A4A4A400A4ULL, +0x2828002828280028ULL, 0x7B7B007B7B7B007BULL, 0xC9C900C9C9C900C9ULL, 0xC1C100C1C1C100C1ULL, +0xE3E300E3E3E300E3ULL, 0xF4F400F4F4F400F4ULL, 0xC7C700C7C7C700C7ULL, 0x9E9E009E9E9E009EULL }; + +const u64bit Camellia_SBOX8[256] = { +0x7070700070707000ULL, 0x8282820082828200ULL, 0x2C2C2C002C2C2C00ULL, 0xECECEC00ECECEC00ULL, +0xB3B3B300B3B3B300ULL, 0x2727270027272700ULL, 0xC0C0C000C0C0C000ULL, 0xE5E5E500E5E5E500ULL, +0xE4E4E400E4E4E400ULL, 0x8585850085858500ULL, 0x5757570057575700ULL, 0x3535350035353500ULL, +0xEAEAEA00EAEAEA00ULL, 0x0C0C0C000C0C0C00ULL, 0xAEAEAE00AEAEAE00ULL, 0x4141410041414100ULL, +0x2323230023232300ULL, 0xEFEFEF00EFEFEF00ULL, 0x6B6B6B006B6B6B00ULL, 0x9393930093939300ULL, +0x4545450045454500ULL, 0x1919190019191900ULL, 0xA5A5A500A5A5A500ULL, 0x2121210021212100ULL, +0xEDEDED00EDEDED00ULL, 0x0E0E0E000E0E0E00ULL, 0x4F4F4F004F4F4F00ULL, 0x4E4E4E004E4E4E00ULL, +0x1D1D1D001D1D1D00ULL, 0x6565650065656500ULL, 0x9292920092929200ULL, 0xBDBDBD00BDBDBD00ULL, +0x8686860086868600ULL, 0xB8B8B800B8B8B800ULL, 0xAFAFAF00AFAFAF00ULL, 0x8F8F8F008F8F8F00ULL, +0x7C7C7C007C7C7C00ULL, 0xEBEBEB00EBEBEB00ULL, 0x1F1F1F001F1F1F00ULL, 0xCECECE00CECECE00ULL, +0x3E3E3E003E3E3E00ULL, 0x3030300030303000ULL, 0xDCDCDC00DCDCDC00ULL, 0x5F5F5F005F5F5F00ULL, +0x5E5E5E005E5E5E00ULL, 0xC5C5C500C5C5C500ULL, 0x0B0B0B000B0B0B00ULL, 0x1A1A1A001A1A1A00ULL, +0xA6A6A600A6A6A600ULL, 0xE1E1E100E1E1E100ULL, 0x3939390039393900ULL, 0xCACACA00CACACA00ULL, +0xD5D5D500D5D5D500ULL, 0x4747470047474700ULL, 0x5D5D5D005D5D5D00ULL, 0x3D3D3D003D3D3D00ULL, +0xD9D9D900D9D9D900ULL, 0x0101010001010100ULL, 0x5A5A5A005A5A5A00ULL, 0xD6D6D600D6D6D600ULL, +0x5151510051515100ULL, 0x5656560056565600ULL, 0x6C6C6C006C6C6C00ULL, 0x4D4D4D004D4D4D00ULL, +0x8B8B8B008B8B8B00ULL, 0x0D0D0D000D0D0D00ULL, 0x9A9A9A009A9A9A00ULL, 0x6666660066666600ULL, +0xFBFBFB00FBFBFB00ULL, 0xCCCCCC00CCCCCC00ULL, 0xB0B0B000B0B0B000ULL, 0x2D2D2D002D2D2D00ULL, +0x7474740074747400ULL, 0x1212120012121200ULL, 0x2B2B2B002B2B2B00ULL, 0x2020200020202000ULL, +0xF0F0F000F0F0F000ULL, 0xB1B1B100B1B1B100ULL, 0x8484840084848400ULL, 0x9999990099999900ULL, +0xDFDFDF00DFDFDF00ULL, 0x4C4C4C004C4C4C00ULL, 0xCBCBCB00CBCBCB00ULL, 0xC2C2C200C2C2C200ULL, +0x3434340034343400ULL, 0x7E7E7E007E7E7E00ULL, 0x7676760076767600ULL, 0x0505050005050500ULL, +0x6D6D6D006D6D6D00ULL, 0xB7B7B700B7B7B700ULL, 0xA9A9A900A9A9A900ULL, 0x3131310031313100ULL, +0xD1D1D100D1D1D100ULL, 0x1717170017171700ULL, 0x0404040004040400ULL, 0xD7D7D700D7D7D700ULL, +0x1414140014141400ULL, 0x5858580058585800ULL, 0x3A3A3A003A3A3A00ULL, 0x6161610061616100ULL, +0xDEDEDE00DEDEDE00ULL, 0x1B1B1B001B1B1B00ULL, 0x1111110011111100ULL, 0x1C1C1C001C1C1C00ULL, +0x3232320032323200ULL, 0x0F0F0F000F0F0F00ULL, 0x9C9C9C009C9C9C00ULL, 0x1616160016161600ULL, +0x5353530053535300ULL, 0x1818180018181800ULL, 0xF2F2F200F2F2F200ULL, 0x2222220022222200ULL, +0xFEFEFE00FEFEFE00ULL, 0x4444440044444400ULL, 0xCFCFCF00CFCFCF00ULL, 0xB2B2B200B2B2B200ULL, +0xC3C3C300C3C3C300ULL, 0xB5B5B500B5B5B500ULL, 0x7A7A7A007A7A7A00ULL, 0x9191910091919100ULL, +0x2424240024242400ULL, 0x0808080008080800ULL, 0xE8E8E800E8E8E800ULL, 0xA8A8A800A8A8A800ULL, +0x6060600060606000ULL, 0xFCFCFC00FCFCFC00ULL, 0x6969690069696900ULL, 0x5050500050505000ULL, +0xAAAAAA00AAAAAA00ULL, 0xD0D0D000D0D0D000ULL, 0xA0A0A000A0A0A000ULL, 0x7D7D7D007D7D7D00ULL, +0xA1A1A100A1A1A100ULL, 0x8989890089898900ULL, 0x6262620062626200ULL, 0x9797970097979700ULL, +0x5454540054545400ULL, 0x5B5B5B005B5B5B00ULL, 0x1E1E1E001E1E1E00ULL, 0x9595950095959500ULL, +0xE0E0E000E0E0E000ULL, 0xFFFFFF00FFFFFF00ULL, 0x6464640064646400ULL, 0xD2D2D200D2D2D200ULL, +0x1010100010101000ULL, 0xC4C4C400C4C4C400ULL, 0x0000000000000000ULL, 0x4848480048484800ULL, +0xA3A3A300A3A3A300ULL, 0xF7F7F700F7F7F700ULL, 0x7575750075757500ULL, 0xDBDBDB00DBDBDB00ULL, +0x8A8A8A008A8A8A00ULL, 0x0303030003030300ULL, 0xE6E6E600E6E6E600ULL, 0xDADADA00DADADA00ULL, +0x0909090009090900ULL, 0x3F3F3F003F3F3F00ULL, 0xDDDDDD00DDDDDD00ULL, 0x9494940094949400ULL, +0x8787870087878700ULL, 0x5C5C5C005C5C5C00ULL, 0x8383830083838300ULL, 0x0202020002020200ULL, +0xCDCDCD00CDCDCD00ULL, 0x4A4A4A004A4A4A00ULL, 0x9090900090909000ULL, 0x3333330033333300ULL, +0x7373730073737300ULL, 0x6767670067676700ULL, 0xF6F6F600F6F6F600ULL, 0xF3F3F300F3F3F300ULL, +0x9D9D9D009D9D9D00ULL, 0x7F7F7F007F7F7F00ULL, 0xBFBFBF00BFBFBF00ULL, 0xE2E2E200E2E2E200ULL, +0x5252520052525200ULL, 0x9B9B9B009B9B9B00ULL, 0xD8D8D800D8D8D800ULL, 0x2626260026262600ULL, +0xC8C8C800C8C8C800ULL, 0x3737370037373700ULL, 0xC6C6C600C6C6C600ULL, 0x3B3B3B003B3B3B00ULL, +0x8181810081818100ULL, 0x9696960096969600ULL, 0x6F6F6F006F6F6F00ULL, 0x4B4B4B004B4B4B00ULL, +0x1313130013131300ULL, 0xBEBEBE00BEBEBE00ULL, 0x6363630063636300ULL, 0x2E2E2E002E2E2E00ULL, +0xE9E9E900E9E9E900ULL, 0x7979790079797900ULL, 0xA7A7A700A7A7A700ULL, 0x8C8C8C008C8C8C00ULL, +0x9F9F9F009F9F9F00ULL, 0x6E6E6E006E6E6E00ULL, 0xBCBCBC00BCBCBC00ULL, 0x8E8E8E008E8E8E00ULL, +0x2929290029292900ULL, 0xF5F5F500F5F5F500ULL, 0xF9F9F900F9F9F900ULL, 0xB6B6B600B6B6B600ULL, +0x2F2F2F002F2F2F00ULL, 0xFDFDFD00FDFDFD00ULL, 0xB4B4B400B4B4B400ULL, 0x5959590059595900ULL, +0x7878780078787800ULL, 0x9898980098989800ULL, 0x0606060006060600ULL, 0x6A6A6A006A6A6A00ULL, +0xE7E7E700E7E7E700ULL, 0x4646460046464600ULL, 0x7171710071717100ULL, 0xBABABA00BABABA00ULL, +0xD4D4D400D4D4D400ULL, 0x2525250025252500ULL, 0xABABAB00ABABAB00ULL, 0x4242420042424200ULL, +0x8888880088888800ULL, 0xA2A2A200A2A2A200ULL, 0x8D8D8D008D8D8D00ULL, 0xFAFAFA00FAFAFA00ULL, +0x7272720072727200ULL, 0x0707070007070700ULL, 0xB9B9B900B9B9B900ULL, 0x5555550055555500ULL, +0xF8F8F800F8F8F800ULL, 0xEEEEEE00EEEEEE00ULL, 0xACACAC00ACACAC00ULL, 0x0A0A0A000A0A0A00ULL, +0x3636360036363600ULL, 0x4949490049494900ULL, 0x2A2A2A002A2A2A00ULL, 0x6868680068686800ULL, +0x3C3C3C003C3C3C00ULL, 0x3838380038383800ULL, 0xF1F1F100F1F1F100ULL, 0xA4A4A400A4A4A400ULL, +0x4040400040404000ULL, 0x2828280028282800ULL, 0xD3D3D300D3D3D300ULL, 0x7B7B7B007B7B7B00ULL, +0xBBBBBB00BBBBBB00ULL, 0xC9C9C900C9C9C900ULL, 0x4343430043434300ULL, 0xC1C1C100C1C1C100ULL, +0x1515150015151500ULL, 0xE3E3E300E3E3E300ULL, 0xADADAD00ADADAD00ULL, 0xF4F4F400F4F4F400ULL, +0x7777770077777700ULL, 0xC7C7C700C7C7C700ULL, 0x8080800080808000ULL, 0x9E9E9E009E9E9E00ULL }; + +} + + +namespace Botan { + +extern "C" { + +#ifdef Q_OS_UNIX +/* +* Helper Macros for x86 Assembly +*/ +#ifndef ASM + #define ASM(x) x "\n\t" +#endif + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \ + ASM("movl %[carry], 4*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("addl 4*" #INDEX "(%[z]),%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX " (%[z])") + +#define DO_8_TIMES(MACRO, ARG) \ + MACRO(ARG, 0) \ + MACRO(ARG, 1) \ + MACRO(ARG, 2) \ + MACRO(ARG, 3) \ + MACRO(ARG, 4) \ + MACRO(ARG, 5) \ + MACRO(ARG, 6) \ + MACRO(ARG, 7) + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorl %[carry]") \ + CORE_CODE \ + ASM("sbbl %[carry],%[carry]") \ + ASM("negl %[carry]") + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + asm( + ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) + { + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mull %[y]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) + { + asm( + ASM("mull %[y]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + ASM("addl %[x],%[w0]") + ASM("adcl %[y],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + } +#else +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { + x[0] = word_add(x[0], y[0], &carry); + x[1] = word_add(x[1], y[1], &carry); + x[2] = word_add(x[2], y[2], &carry); + x[3] = word_add(x[3], y[3], &carry); + x[4] = word_add(x[4], y[4], &carry); + x[5] = word_add(x[5], y[5], &carry); + x[6] = word_add(x[6], y[6], &carry); + x[7] = word_add(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], + const word y[8], word carry) + { + z[0] = word_add(x[0], y[0], &carry); + z[1] = word_add(x[1], y[1], &carry); + z[2] = word_add(x[2], y[2], &carry); + z[3] = word_add(x[3], y[3], &carry); + z[4] = word_add(x[4], y[4], &carry); + z[5] = word_add(x[5], y[5], &carry); + z[6] = word_add(x[6], y[6], &carry); + z[7] = word_add(x[7], y[7], &carry); + return carry; + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { + x[0] = word_sub(x[0], y[0], &carry); + x[1] = word_sub(x[1], y[1], &carry); + x[2] = word_sub(x[2], y[2], &carry); + x[3] = word_sub(x[3], y[3], &carry); + x[4] = word_sub(x[4], y[4], &carry); + x[5] = word_sub(x[5], y[5], &carry); + x[6] = word_sub(x[6], y[6], &carry); + x[7] = word_sub(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { + x[0] = word_sub(y[0], x[0], &carry); + x[1] = word_sub(y[1], x[1], &carry); + x[2] = word_sub(y[2], x[2], &carry); + x[3] = word_sub(y[3], x[3], &carry); + x[4] = word_sub(y[4], x[4], &carry); + x[5] = word_sub(y[5], x[5], &carry); + x[6] = word_sub(y[6], x[6], &carry); + x[7] = word_sub(y[7], x[7], &carry); + return carry; + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], + const word y[8], word carry) + { + z[0] = word_sub(x[0], y[0], &carry); + z[1] = word_sub(x[1], y[1], &carry); + z[2] = word_sub(x[2], y[2], &carry); + z[3] = word_sub(x[3], y[3], &carry); + z[4] = word_sub(x[4], y[4], &carry); + z[5] = word_sub(x[5], y[5], &carry); + z[6] = word_sub(x[6], y[6], &carry); + z[7] = word_sub(x[7], y[7], &carry); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { + x[0] = word_madd2(x[0], y, &carry); + x[1] = word_madd2(x[1], y, &carry); + x[2] = word_madd2(x[2], y, &carry); + x[3] = word_madd2(x[3], y, &carry); + x[4] = word_madd2(x[4], y, &carry); + x[5] = word_madd2(x[5], y, &carry); + x[6] = word_madd2(x[6], y, &carry); + x[7] = word_madd2(x[7], y, &carry); + return carry; + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { + z[0] = word_madd2(x[0], y, &carry); + z[1] = word_madd2(x[1], y, &carry); + z[2] = word_madd2(x[2], y, &carry); + z[3] = word_madd2(x[3], y, &carry); + z[4] = word_madd2(x[4], y, &carry); + z[5] = word_madd2(x[5], y, &carry); + z[6] = word_madd2(x[6], y, &carry); + z[7] = word_madd2(x[7], y, &carry); + return carry; + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { + z[0] = word_madd3(x[0], y, z[0], &carry); + z[1] = word_madd3(x[1], y, z[1], &carry); + z[2] = word_madd3(x[2], y, z[2], &carry); + z[3] = word_madd3(x[3], y, z[3], &carry); + z[4] = word_madd3(x[4], y, z[4], &carry); + z[5] = word_madd3(x[5], y, z[5], &carry); + z[6] = word_madd3(x[6], y, z[6], &carry); + z[7] = word_madd3(x[7], y, z[7], &carry); + return carry; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b) + { + word carry = *w0; + *w0 = word_madd2(a, b, &carry); + *w1 += carry; + *w2 += (*w1 < carry) ? 1 : 0; + } + +/* +* Multiply-Add Accumulator +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b) + { + word carry = 0; + a = word_madd2(a, b, &carry); + b = carry; + + word top = (b >> (BOTAN_MP_WORD_BITS-1)); + b <<= 1; + b |= (a >> (BOTAN_MP_WORD_BITS-1)); + a <<= 1; + + carry = 0; + *w0 = word_add(*w0, a, &carry); + *w1 = word_add(*w1, b, &carry); + *w2 = word_add(*w2, top, &carry); + } + +#endif + +} + +} + +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Create an OctetString from RNG output +*/ +OctetString::OctetString(RandomNumberGenerator& rng, + size_t length) + { + bits = rng.random_vec(length); + } + +/* +* Create an OctetString from a hex string +*/ +void OctetString::change(const std::string& hex_string) + { + bits.resize(1 + hex_string.length() / 2); + bits.resize(hex_decode(&bits[0], hex_string)); + } + +/* +* Create an OctetString from a byte string +*/ +void OctetString::change(const byte in[], size_t n) + { + bits.resize(n); + bits.copy(in, n); + } + +/* +* Set the parity of each key byte to odd +*/ +void OctetString::set_odd_parity() + { + const byte ODD_PARITY[256] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, + 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, + 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, + 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, + 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, + 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, + 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, + 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, + 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, + 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, + 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, + 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, + 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, + 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, + 0xFD, 0xFD, 0xFE, 0xFE }; + + for(size_t j = 0; j != bits.size(); ++j) + bits[j] = ODD_PARITY[bits[j]]; + } + +/* +* Hex encode an OctetString +*/ +std::string OctetString::as_string() const + { + return hex_encode(&bits[0], bits.size()); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { zeroise(bits); return (*this); } + xor_buf(&bits[0], k.begin(), std::min(length(), k.length())); + return (*this); + } + +/* +* Equality Operation for OctetStrings +*/ +bool operator==(const OctetString& s1, const OctetString& s2) + { + return (s1.bits_of() == s2.bits_of()); + } + +/* +* Unequality Operation for OctetStrings +*/ +bool operator!=(const OctetString& s1, const OctetString& s2) + { + return !(s1 == s2); + } + +/* +* Append Operation for OctetStrings +*/ +OctetString operator+(const OctetString& k1, const OctetString& k2) + { + SecureVector out; + out += k1.bits_of(); + out += k2.bits_of(); + return OctetString(out); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + SecureVector ret(std::max(k1.length(), k2.length())); + ret.copy(k1.begin(), k1.length()); + xor_buf(ret, k2.begin(), k2.length()); + return OctetString(ret); + } + +} +/* +* Algorithm Factory +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + + +#include + +namespace Botan { + +namespace { + +/* +* Template functions for the factory prototype/search algorithm +*/ +template +T* engine_get_algo(Engine*, + const SCAN_Name&, + Algorithm_Factory&) + { return 0; } + +template<> +BlockCipher* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_block_cipher(request, af); } + +template<> +StreamCipher* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_stream_cipher(request, af); } + +template<> +HashFunction* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_hash(request, af); } + +template<> +MessageAuthenticationCode* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_mac(request, af); } + +template<> +PBKDF* engine_get_algo(Engine* engine, + const SCAN_Name& request, + Algorithm_Factory& af) + { return engine->find_pbkdf(request, af); } + +template +const T* factory_prototype(const std::string& algo_spec, + const std::string& provider, + const std::vector& engines, + Algorithm_Factory& af, + Algorithm_Cache* cache) + { + if(const T* cache_hit = cache->get(algo_spec, provider)) + return cache_hit; + + SCAN_Name scan_name(algo_spec); + + if(scan_name.cipher_mode() != "") + return 0; + + for(size_t i = 0; i != engines.size(); ++i) + { + if(provider == "" || engines[i]->provider_name() == provider) + { + if(T* impl = engine_get_algo(engines[i], scan_name, af)) + cache->add(impl, algo_spec, engines[i]->provider_name()); + } + } + + return cache->get(algo_spec, provider); + } + +} + +/* +* Setup caches +*/ +Algorithm_Factory::Algorithm_Factory(Mutex_Factory& mf) + { + block_cipher_cache = new Algorithm_Cache(mf.make()); + stream_cipher_cache = new Algorithm_Cache(mf.make()); + hash_cache = new Algorithm_Cache(mf.make()); + mac_cache = new Algorithm_Cache(mf.make()); + pbkdf_cache = new Algorithm_Cache(mf.make()); + } + +/* +* Delete all engines +*/ +Algorithm_Factory::~Algorithm_Factory() + { + delete block_cipher_cache; + delete stream_cipher_cache; + delete hash_cache; + delete mac_cache; + delete pbkdf_cache; + + std::for_each(engines.begin(), engines.end(), del_fun()); + } + +void Algorithm_Factory::clear_caches() + { + block_cipher_cache->clear_cache(); + stream_cipher_cache->clear_cache(); + hash_cache->clear_cache(); + mac_cache->clear_cache(); + pbkdf_cache->clear_cache(); + } + +void Algorithm_Factory::add_engine(Engine* engine) + { + clear_caches(); + engines.push_back(engine); + } + +/* +* Set the preferred provider for an algorithm +*/ +void Algorithm_Factory::set_preferred_provider(const std::string& algo_spec, + const std::string& provider) + { + if(prototype_block_cipher(algo_spec)) + block_cipher_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_stream_cipher(algo_spec)) + stream_cipher_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_hash_function(algo_spec)) + hash_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_mac(algo_spec)) + mac_cache->set_preferred_provider(algo_spec, provider); + else if(prototype_pbkdf(algo_spec)) + pbkdf_cache->set_preferred_provider(algo_spec, provider); + } + +/* +* Get an engine out of the list +*/ +Engine* Algorithm_Factory::get_engine_n(size_t n) const + { + if(n >= engines.size()) + return 0; + return engines[n]; + } + +/* +* Return the possible providers of a request +* Note: assumes you don't have different types by the same name +*/ +std::vector +Algorithm_Factory::providers_of(const std::string& algo_spec) + { + /* The checks with if(prototype_X(algo_spec)) have the effect of + forcing a full search, since otherwise there might not be any + providers at all in the cache. + */ + + if(prototype_block_cipher(algo_spec)) + return block_cipher_cache->providers_of(algo_spec); + else if(prototype_stream_cipher(algo_spec)) + return stream_cipher_cache->providers_of(algo_spec); + else if(prototype_hash_function(algo_spec)) + return hash_cache->providers_of(algo_spec); + else if(prototype_mac(algo_spec)) + return mac_cache->providers_of(algo_spec); + else if(prototype_pbkdf(algo_spec)) + return pbkdf_cache->providers_of(algo_spec); + else + return std::vector(); + } + +/* +* Return the prototypical block cipher corresponding to this request +*/ +const BlockCipher* +Algorithm_Factory::prototype_block_cipher(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, block_cipher_cache); + } + +/* +* Return the prototypical stream cipher corresponding to this request +*/ +const StreamCipher* +Algorithm_Factory::prototype_stream_cipher(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, stream_cipher_cache); + } + +/* +* Return the prototypical object corresponding to this request (if found) +*/ +const HashFunction* +Algorithm_Factory::prototype_hash_function(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, engines, + *this, hash_cache); + } + +/* +* Return the prototypical object corresponding to this request +*/ +const MessageAuthenticationCode* +Algorithm_Factory::prototype_mac(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, + engines, + *this, mac_cache); + } + +/* +* Return the prototypical object corresponding to this request +*/ +const PBKDF* +Algorithm_Factory::prototype_pbkdf(const std::string& algo_spec, + const std::string& provider) + { + return factory_prototype(algo_spec, provider, + engines, + *this, pbkdf_cache); + } + +/* +* Return a new block cipher corresponding to this request +*/ +BlockCipher* +Algorithm_Factory::make_block_cipher(const std::string& algo_spec, + const std::string& provider) + { + if(const BlockCipher* proto = prototype_block_cipher(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new stream cipher corresponding to this request +*/ +StreamCipher* +Algorithm_Factory::make_stream_cipher(const std::string& algo_spec, + const std::string& provider) + { + if(const StreamCipher* proto = prototype_stream_cipher(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +HashFunction* +Algorithm_Factory::make_hash_function(const std::string& algo_spec, + const std::string& provider) + { + if(const HashFunction* proto = prototype_hash_function(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +MessageAuthenticationCode* +Algorithm_Factory::make_mac(const std::string& algo_spec, + const std::string& provider) + { + if(const MessageAuthenticationCode* proto = prototype_mac(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Return a new object corresponding to this request +*/ +PBKDF* +Algorithm_Factory::make_pbkdf(const std::string& algo_spec, + const std::string& provider) + { + if(const PBKDF* proto = prototype_pbkdf(algo_spec, provider)) + return proto->clone(); + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Add a new block cipher +*/ +void Algorithm_Factory::add_block_cipher(BlockCipher* block_cipher, + const std::string& provider) + { + block_cipher_cache->add(block_cipher, block_cipher->name(), provider); + } + +/* +* Add a new stream cipher +*/ +void Algorithm_Factory::add_stream_cipher(StreamCipher* stream_cipher, + const std::string& provider) + { + stream_cipher_cache->add(stream_cipher, stream_cipher->name(), provider); + } + +/* +* Add a new hash +*/ +void Algorithm_Factory::add_hash_function(HashFunction* hash, + const std::string& provider) + { + hash_cache->add(hash, hash->name(), provider); + } + +/* +* Add a new mac +*/ +void Algorithm_Factory::add_mac(MessageAuthenticationCode* mac, + const std::string& provider) + { + mac_cache->add(mac, mac->name(), provider); + } + +/* +* Add a new PBKDF +*/ +void Algorithm_Factory::add_pbkdf(PBKDF* pbkdf, + const std::string& provider) + { + pbkdf_cache->add(pbkdf, pbkdf->name(), provider); + } + +} +/* +* Default provider weights for Algorithm_Cache +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/** +* Return a static provider weighing +*/ +size_t static_provider_weight(const std::string& prov_name) + { + /* + * Prefer asm over C++, but prefer anything over OpenSSL or GNU MP; to use + * them, set the provider explicitly for the algorithms you want + */ + + if(prov_name == "aes_isa") return 9; + if(prov_name == "simd") return 8; + if(prov_name == "asm") return 7; + + if(prov_name == "core") return 5; + + if(prov_name == "openssl") return 2; + if(prov_name == "gmp") return 1; + + return 0; // other/unknown + } + +} + +#ifdef Q_OS_UNIX +/* +* Memory Mapping Allocator +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_FAILED + #define MAP_FAILED -1 +#endif + +namespace Botan { + +namespace { + +/* +* MemoryMapping_Allocator Exception +*/ +class BOTAN_DLL MemoryMapping_Failed : public Exception + { + public: + MemoryMapping_Failed(const std::string& msg) : + Exception("MemoryMapping_Allocator: " + msg) {} + }; + +} + +/* +* Memory Map a File into Memory +*/ +void* MemoryMapping_Allocator::alloc_block(size_t n) + { + class TemporaryFile + { + public: + int get_fd() const { return fd; } + + TemporaryFile(const std::string& base) + { + const std::string mkstemp_template = base + "XXXXXX"; + + std::vector filepath(mkstemp_template.begin(), + mkstemp_template.end()); + filepath.push_back(0); // add terminating NULL + + mode_t old_umask = ::umask(077); + fd = ::mkstemp(&filepath[0]); + ::umask(old_umask); + + if(fd == -1) + throw MemoryMapping_Failed("Temporary file allocation failed"); + + if(::unlink(&filepath[0]) != 0) + throw MemoryMapping_Failed("Could not unlink temporary file"); + } + + ~TemporaryFile() Q_DECL_NOEXCEPT_EXPR(false) + { + /* + * We can safely close here, because post-mmap the file + * will continue to exist until the mmap is unmapped from + * our address space upon deallocation (or process exit). + */ + if(fd != -1 && ::close(fd) == -1) + throw MemoryMapping_Failed("Could not close file"); + } + private: + int fd; + }; + + TemporaryFile file("/tmp/botan_"); + + if(file.get_fd() == -1) + throw MemoryMapping_Failed("Could not create file"); + + std::vector zeros(4096); + + size_t remaining = n; + + while(remaining) + { + const size_t write_try = std::min(zeros.size(), remaining); + + ssize_t wrote_got = ::write(file.get_fd(), + &zeros[0], + write_try); + + if(wrote_got == -1 && errno != EINTR) + throw MemoryMapping_Failed("Could not write to file"); + + remaining -= wrote_got; + } + +#ifndef MAP_NOSYNC + #define MAP_NOSYNC 0 +#endif + + void* ptr = ::mmap(0, n, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_NOSYNC, + file.get_fd(), 0); + + if(ptr == static_cast(MAP_FAILED)) + throw MemoryMapping_Failed("Could not map file"); + + return ptr; + } + +/* +* Remove a Memory Mapping +*/ +void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n) + { + if(ptr == 0) + return; + + const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 }; + + // The char* casts are for Solaris, args are void* on most other systems + + for(size_t i = 0; i != sizeof(PATTERNS); ++i) + { + std::memset(ptr, PATTERNS[i], n); + + if(::msync(static_cast(ptr), n, MS_SYNC)) + throw MemoryMapping_Failed("Sync operation failed"); + } + + if(::munmap(static_cast(ptr), n)) + throw MemoryMapping_Failed("Could not unmap file"); + } + +} +#endif + +/* +* Pooling Allocator +* (C) 1999-2008 Jack Lloyd +* 2005 Matthew Gregan +* 2005-2006 Matt Johnston +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Memory_Block Constructor +*/ +Pooling_Allocator::Memory_Block::Memory_Block(void* buf) + { + buffer = static_cast(buf); + bitmap = 0; + buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE); + } + +/* +* See if ptr is contained by this block +*/ +bool Pooling_Allocator::Memory_Block::contains(void* ptr, + size_t length) const + { + return ((buffer <= ptr) && + (buffer_end >= static_cast(ptr) + length * BLOCK_SIZE)); + } + +/* +* Allocate some memory, if possible +*/ +byte* Pooling_Allocator::Memory_Block::alloc(size_t n) + { + if(n == 0 || n > BITMAP_SIZE) + return 0; + + if(n == BITMAP_SIZE) + { + if(bitmap) + return 0; + else + { + bitmap = ~bitmap; + return buffer; + } + } + + bitmap_type mask = (static_cast(1) << n) - 1; + size_t offset = 0; + + while(bitmap & mask) + { + mask <<= 1; + ++offset; + + if((bitmap & mask) == 0) + break; + if(mask >> 63) + break; + } + + if(bitmap & mask) + return 0; + + bitmap |= mask; + return buffer + offset * BLOCK_SIZE; + } + +/* +* Mark this memory as free, if we own it +*/ +void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks) + { + clear_mem(static_cast(ptr), blocks * BLOCK_SIZE); + + const size_t offset = (static_cast(ptr) - buffer) / BLOCK_SIZE; + + if(offset == 0 && blocks == BITMAP_SIZE) + bitmap = ~bitmap; + else + { + for(size_t j = 0; j != blocks; ++j) + bitmap &= ~(static_cast(1) << (j+offset)); + } + } + +/* +* Pooling_Allocator Constructor +*/ +Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m) + { + last_used = blocks.begin(); + } + +/* +* Pooling_Allocator Destructor +*/ +Pooling_Allocator::~Pooling_Allocator() + { + delete mutex; + if(blocks.size()) + throw Invalid_State("Pooling_Allocator: Never released memory"); + } + +/* +* Free all remaining memory +*/ +void Pooling_Allocator::destroy() + { + Mutex_Holder lock(mutex); + + blocks.clear(); + + for(size_t j = 0; j != allocated.size(); ++j) + dealloc_block(allocated[j].first, allocated[j].second); + allocated.clear(); + } + +/* +* Allocation +*/ +void* Pooling_Allocator::allocate(size_t n) + { + const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); + const size_t BLOCK_SIZE = Memory_Block::block_size(); + + Mutex_Holder lock(mutex); + + if(n <= BITMAP_SIZE * BLOCK_SIZE) + { + const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; + + byte* mem = allocate_blocks(block_no); + if(mem) + return mem; + + get_more_core(BOTAN_MEM_POOL_CHUNK_SIZE); + + mem = allocate_blocks(block_no); + if(mem) + return mem; + + throw Memory_Exhaustion(); + } + + void* new_buf = alloc_block(n); + if(new_buf) + return new_buf; + + throw Memory_Exhaustion(); + } + +/* +* Deallocation +*/ +void Pooling_Allocator::deallocate(void* ptr, size_t n) + { + const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); + const size_t BLOCK_SIZE = Memory_Block::block_size(); + + if(ptr == 0 && n == 0) + return; + + Mutex_Holder lock(mutex); + + if(n > BITMAP_SIZE * BLOCK_SIZE) + dealloc_block(ptr, n); + else + { + const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; + + std::vector::iterator i = + std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); + + if(i == blocks.end() || !i->contains(ptr, block_no)) + throw Invalid_State("Pointer released to the wrong allocator"); + + i->free(ptr, block_no); + } + } + +/* +* Try to get some memory from an existing block +*/ +byte* Pooling_Allocator::allocate_blocks(size_t n) + { + if(blocks.empty()) + return 0; + + std::vector::iterator i = last_used; + + do + { + byte* mem = i->alloc(n); + if(mem) + { + last_used = i; + return mem; + } + + ++i; + if(i == blocks.end()) + i = blocks.begin(); + } + while(i != last_used); + + return 0; + } + +/* +* Allocate more memory for the pool +*/ +void Pooling_Allocator::get_more_core(size_t in_bytes) + { + const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); + const size_t BLOCK_SIZE = Memory_Block::block_size(); + + const size_t TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE; + + // upper bound on allocation is 1 MiB + in_bytes = std::min(in_bytes, 1024 * 1024); + + const size_t in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE; + const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE; + + void* ptr = alloc_block(to_allocate); + if(ptr == 0) + throw Memory_Exhaustion(); + + allocated.push_back(std::make_pair(ptr, to_allocate)); + + for(size_t j = 0; j != in_blocks; ++j) + { + byte* byte_ptr = static_cast(ptr); + blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE)); + } + + std::sort(blocks.begin(), blocks.end()); + last_used = std::lower_bound(blocks.begin(), blocks.end(), + Memory_Block(ptr)); + } + +} +/* +* Basic Allocators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Perform Memory Allocation +*/ +void* do_malloc(size_t n, bool do_lock) + { + void* ptr = std::malloc(n); + + if(!ptr) + return 0; + + if(do_lock) + lock_mem(ptr, n); + + std::memset(ptr, 0, n); + return ptr; + } + +/* +* Perform Memory Deallocation +*/ +void do_free(void* ptr, size_t n, bool do_lock) + { + if(!ptr) + return; + + std::memset(ptr, 0, n); + if(do_lock) + unlock_mem(ptr, n); + + std::free(ptr); + } + +} + +/* +* Malloc_Allocator's Allocation +*/ +void* Malloc_Allocator::allocate(size_t n) + { + void* ptr = do_malloc(n, false); + if(!ptr) + throw Memory_Exhaustion(); + return ptr; + } + +/* +* Malloc_Allocator's Deallocation +*/ +void Malloc_Allocator::deallocate(void* ptr, size_t n) + { + do_free(ptr, n, false); + } + +/* +* Locking_Allocator's Allocation +*/ +void* Locking_Allocator::alloc_block(size_t n) + { + return do_malloc(n, true); + } + +/* +* Locking_Allocator's Deallocation +*/ +void Locking_Allocator::dealloc_block(void* ptr, size_t n) + { + do_free(ptr, n, true); + } + +/* +* Get an allocator +*/ +Allocator* Allocator::get(bool locking) + { + std::string type = ""; + if(!locking) + type = "malloc"; + + Allocator* alloc = global_state().get_allocator(type); + if(alloc) + return alloc; + + throw Internal_Error("Couldn't find an allocator to use in get_allocator"); + } + +} +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + const MemoryRegion& param) + { + oid = alg_id; + parameters = param; + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + const MemoryRegion& param) + { + oid = OIDS::lookup(alg_id); + parameters = param; + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + Encoding_Option option) + { + const byte DER_NULL[] = { 0x05, 0x00 }; + + oid = alg_id; + + if(option == USE_NULL_PARAM) + { + parameters += std::pair(DER_NULL, sizeof(DER_NULL)); + } + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + Encoding_Option option) + { + const byte DER_NULL[] = { 0x05, 0x00 }; + + oid = OIDS::lookup(alg_id); + + if(option == USE_NULL_PARAM) + { + parameters += std::pair(DER_NULL, sizeof(DER_NULL)); + } + } + +/* +* Compare two AlgorithmIdentifiers +*/ +bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + if(a1.oid != a2.oid) + return false; + if(a1.parameters != a2.parameters) + return false; + return true; + } + +/* +* Compare two AlgorithmIdentifiers +*/ +bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + return !(a1 == a2); + } + +/* +* DER encode an AlgorithmIdentifier +*/ +void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +/* +* Decode a BER encoded AlgorithmIdentifier +*/ +void AlgorithmIdentifier::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +} +/* +* AlternativeName +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Check if type is a known ASN.1 string type +*/ +bool is_string_type(ASN1_Tag tag) + { + return (tag == NUMERIC_STRING || + tag == PRINTABLE_STRING || + tag == VISIBLE_STRING || + tag == T61_STRING || + tag == IA5_STRING || + tag == UTF8_STRING || + tag == BMP_STRING); + } + +} + +/* +* Create an AlternativeName +*/ +AlternativeName::AlternativeName(const std::string& email_addr, + const std::string& uri, + const std::string& dns, + const std::string& ip) + { + add_attribute("RFC822", email_addr); + add_attribute("DNS", dns); + add_attribute("URI", uri); + add_attribute("IP", ip); + } + +/* +* Add an attribute to an alternative name +*/ +void AlternativeName::add_attribute(const std::string& type, + const std::string& str) + { + if(type == "" || str == "") + return; + + typedef std::multimap::iterator iter; + std::pair range = alt_info.equal_range(type); + for(iter j = range.first; j != range.second; ++j) + if(j->second == str) + return; + + multimap_insert(alt_info, type, str); + } + +/* +* Add an OtherName field +*/ +void AlternativeName::add_othername(const OID& oid, const std::string& value, + ASN1_Tag type) + { + if(value == "") + return; + multimap_insert(othernames, oid, ASN1_String(value, type)); + } + +/* +* Get the attributes of this alternative name +*/ +std::multimap AlternativeName::get_attributes() const + { + return alt_info; + } + +/* +* Get the otherNames +*/ +std::multimap AlternativeName::get_othernames() const + { + return othernames; + } + +/* +* Return all of the alternative names +*/ +std::multimap AlternativeName::contents() const + { + std::multimap names; + + typedef std::multimap::const_iterator rdn_iter; + for(rdn_iter j = alt_info.begin(); j != alt_info.end(); ++j) + multimap_insert(names, j->first, j->second); + + typedef std::multimap::const_iterator on_iter; + for(on_iter j = othernames.begin(); j != othernames.end(); ++j) + multimap_insert(names, OIDS::lookup(j->first), j->second.value()); + + return names; + } + +/* +* Return if this object has anything useful +*/ +bool AlternativeName::has_items() const + { + return (alt_info.size() > 0 || othernames.size() > 0); + } + +namespace { + +/* +* DER encode an AlternativeName entry +*/ +void encode_entries(DER_Encoder& encoder, + const std::multimap& attr, + const std::string& type, ASN1_Tag tagging) + { + typedef std::multimap::const_iterator iter; + + std::pair range = attr.equal_range(type); + for(iter j = range.first; j != range.second; ++j) + { + if(type == "RFC822" || type == "DNS" || type == "URI") + { + ASN1_String asn1_string(j->second, IA5_STRING); + encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.iso_8859()); + } + else if(type == "IP") + { + const u32bit ip = string_to_ipv4(j->second); + byte ip_buf[4] = { 0 }; + store_be(ip, ip_buf); + encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4); + } + } + } + +} + +/* +* DER encode an AlternativeName extension +*/ +void AlternativeName::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + encode_entries(der, alt_info, "RFC822", ASN1_Tag(1)); + encode_entries(der, alt_info, "DNS", ASN1_Tag(2)); + encode_entries(der, alt_info, "URI", ASN1_Tag(6)); + encode_entries(der, alt_info, "IP", ASN1_Tag(7)); + + std::multimap::const_iterator i; + for(i = othernames.begin(); i != othernames.end(); ++i) + { + der.start_explicit(0) + .encode(i->first) + .start_explicit(0) + .encode(i->second) + .end_explicit() + .end_explicit(); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded AlternativeName +*/ +void AlternativeName::decode_from(BER_Decoder& source) + { + BER_Decoder names = source.start_cons(SEQUENCE); + + while(names.more_items()) + { + BER_Object obj = names.get_next_object(); + if((obj.class_tag != CONTEXT_SPECIFIC) && + (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))) + continue; + + const ASN1_Tag tag = obj.type_tag; + + if(tag == 0) + { + BER_Decoder othername(obj.value); + + OID oid; + othername.decode(oid); + if(othername.more_items()) + { + BER_Object othername_value_outer = othername.get_next_object(); + othername.verify_end(); + + if(othername_value_outer.type_tag != ASN1_Tag(0) || + othername_value_outer.class_tag != + (CONTEXT_SPECIFIC | CONSTRUCTED) + ) + throw Decoding_Error("Invalid tags on otherName value"); + + BER_Decoder othername_value_inner(othername_value_outer.value); + + BER_Object value = othername_value_inner.get_next_object(); + othername_value_inner.verify_end(); + + const ASN1_Tag value_type = value.type_tag; + + if(is_string_type(value_type) && value.class_tag == UNIVERSAL) + add_othername(oid, ASN1::to_string(value), value_type); + } + } + else if(tag == 1 || tag == 2 || tag == 6) + { + const std::string value = Charset::transcode(ASN1::to_string(obj), + LATIN1_CHARSET, + LOCAL_CHARSET); + + if(tag == 1) add_attribute("RFC822", value); + if(tag == 2) add_attribute("DNS", value); + if(tag == 6) add_attribute("URI", value); + } + else if(tag == 7) + { + if(obj.value.size() == 4) + { + const u32bit ip = load_be(&obj.value[0], 0); + add_attribute("IP", ipv4_to_string(ip)); + } + } + + } + } + +} +/* +* Attribute +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create an Attribute +*/ +Attribute::Attribute(const OID& attr_oid, const MemoryRegion& attr_value) + { + oid = attr_oid; + parameters = attr_value; + } + +/* +* Create an Attribute +*/ +Attribute::Attribute(const std::string& attr_oid, + const MemoryRegion& attr_value) + { + oid = OIDS::lookup(attr_oid); + parameters = attr_value; + } + +/* +* DER encode a Attribute +*/ +void Attribute::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded Attribute +*/ +void Attribute::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +} +/* +* ASN.1 Internals +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* BER Decoding Exceptions +*/ +BER_Decoding_Error::BER_Decoding_Error(const std::string& str) : + Decoding_Error("BER: " + str) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : + BER_Decoding_Error(str + ": " + to_string(tag)) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, + ASN1_Tag tag1, ASN1_Tag tag2) : + BER_Decoding_Error(str + ": " + to_string(tag1) + "/" + to_string(tag2)) {} + +namespace ASN1 { + +/* +* Put some arbitrary bytes into a SEQUENCE +*/ +SecureVector put_in_sequence(const MemoryRegion& contents) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .raw_bytes(contents) + .end_cons() + .get_contents(); + } + +/* +* Convert a BER object into a string object +*/ +std::string to_string(const BER_Object& obj) + { + return std::string(reinterpret_cast(&obj.value[0]), + obj.value.size()); + } + +/* +* Do heuristic tests for BER data +*/ +bool maybe_BER(DataSource& source) + { + byte first_byte; + if(!source.peek_byte(first_byte)) + throw Stream_IO_Error("ASN1::maybe_BER: Source was empty"); + + if(first_byte == (SEQUENCE | CONSTRUCTED)) + return true; + return false; + } + +} + +} +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* ASN.1 OID Constructor +*/ +OID::OID(const std::string& oid_str) + { + if(oid_str != "") + { + try + { + id = parse_asn1_oid(oid_str); + } + catch(...) + { + throw Invalid_OID(oid_str); + } + + if(id.size() < 2 || id[0] > 2) + throw Invalid_OID(oid_str); + if((id[0] == 0 || id[0] == 1) && id[1] > 39) + throw Invalid_OID(oid_str); + } + } + +/* +* Clear the current OID +*/ +void OID::clear() + { + id.clear(); + } + +/* +* Return this OID as a string +*/ +std::string OID::as_string() const + { + std::string oid_str; + for(size_t i = 0; i != id.size(); ++i) + { + oid_str += to_string(id[i]); + if(i != id.size() - 1) + oid_str += '.'; + } + return oid_str; + } + +/* +* OID equality comparison +*/ +bool OID::operator==(const OID& oid) const + { + if(id.size() != oid.id.size()) + return false; + for(size_t i = 0; i != id.size(); ++i) + if(id[i] != oid.id[i]) + return false; + return true; + } + +/* +* Append another component to the OID +*/ +OID& OID::operator+=(u32bit component) + { + id.push_back(component); + return (*this); + } + +/* +* Append another component to the OID +*/ +OID operator+(const OID& oid, u32bit component) + { + OID new_oid(oid); + new_oid += component; + return new_oid; + } + +/* +* OID inequality comparison +*/ +bool operator!=(const OID& a, const OID& b) + { + return !(a == b); + } + +/* +* Compare two OIDs +*/ +bool operator<(const OID& a, const OID& b) + { + std::vector oid1 = a.get_id(); + std::vector oid2 = b.get_id(); + + if(oid1.size() < oid2.size()) + return true; + if(oid1.size() > oid2.size()) + return false; + for(size_t i = 0; i != oid1.size(); ++i) + { + if(oid1[i] < oid2[i]) + return true; + if(oid1[i] > oid2[i]) + return false; + } + return false; + } + +/* +* DER encode an OBJECT IDENTIFIER +*/ +void OID::encode_into(DER_Encoder& der) const + { + if(id.size() < 2) + throw Invalid_Argument("OID::encode_into: OID is invalid"); + + MemoryVector encoding; + encoding.push_back(40 * id[0] + id[1]); + + for(size_t i = 2; i != id.size(); ++i) + { + if(id[i] == 0) + encoding.push_back(0); + else + { + size_t blocks = high_bit(id[i]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + for(size_t j = 0; j != blocks - 1; ++j) + encoding.push_back(0x80 | ((id[i] >> 7*(blocks-j-1)) & 0x7F)); + encoding.push_back(id[i] & 0x7F); + } + } + der.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +/* +* Decode a BER encoded OBJECT IDENTIFIER +*/ +void OID::decode_from(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + if(obj.type_tag != OBJECT_ID || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Error decoding OID, unknown tag", + obj.type_tag, obj.class_tag); + if(obj.value.size() < 2) + throw BER_Decoding_Error("OID encoding is too short"); + + + clear(); + id.push_back(obj.value[0] / 40); + id.push_back(obj.value[0] % 40); + + size_t i = 0; + while(i != obj.value.size() - 1) + { + u32bit component = 0; + while(i != obj.value.size() - 1) + { + ++i; + component = (component << 7) + (obj.value[i] & 0x7F); + if(!(obj.value[i] & 0x80)) + break; + } + id.push_back(component); + } + } + +} +/* +* Simple ASN.1 String Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Choose an encoding for the string +*/ +ASN1_Tag choose_encoding(const std::string& str, + const std::string& type) + { + static const byte IS_PRINTABLE[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + for(size_t i = 0; i != str.size(); ++i) + { + if(!IS_PRINTABLE[static_cast(str[i])]) + { + if(type == "utf8") return UTF8_STRING; + if(type == "latin1") return T61_STRING; + throw Invalid_Argument("choose_encoding: Bad string type " + type); + } + } + return PRINTABLE_STRING; + } + +} + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : tag(t) + { + iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); + + if(tag == DIRECTORY_STRING) + tag = choose_encoding(iso_8859_str, "latin1"); + + if(tag != NUMERIC_STRING && + tag != PRINTABLE_STRING && + tag != VISIBLE_STRING && + tag != T61_STRING && + tag != IA5_STRING && + tag != UTF8_STRING && + tag != BMP_STRING) + throw Invalid_Argument("ASN1_String: Unknown string type " + + to_string(tag)); + } + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str) + { + iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); + tag = choose_encoding(iso_8859_str, "latin1"); + } + +/* +* Return this string in ISO 8859-1 encoding +*/ +std::string ASN1_String::iso_8859() const + { + return iso_8859_str; + } + +/* +* Return this string in local encoding +*/ +std::string ASN1_String::value() const + { + return Charset::transcode(iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET); + } + +/* +* Return the type of this string object +*/ +ASN1_Tag ASN1_String::tagging() const + { + return tag; + } + +/* +* DER encode an ASN1_String +*/ +void ASN1_String::encode_into(DER_Encoder& encoder) const + { + std::string value = iso_8859(); + if(tagging() == UTF8_STRING) + value = Charset::transcode(value, LATIN1_CHARSET, UTF8_CHARSET); + encoder.add_object(tagging(), UNIVERSAL, value); + } + +/* +* Decode a BER encoded ASN1_String +*/ +void ASN1_String::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + Character_Set charset_is; + + if(obj.type_tag == BMP_STRING) + charset_is = UCS2_CHARSET; + else if(obj.type_tag == UTF8_STRING) + charset_is = UTF8_CHARSET; + else + charset_is = LATIN1_CHARSET; + + *this = ASN1_String( + Charset::transcode(ASN1::to_string(obj), charset_is, LOCAL_CHARSET), + obj.type_tag); + } + +} +/* +* X.509 Time Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create an X509_Time +*/ +X509_Time::X509_Time(const std::string& time_str) + { + set_to(time_str); + } + +/* +* Create an X509_Time +*/ +X509_Time::X509_Time(u64bit timer) + { + calendar_point cal = calendar_value(timer); + + year = cal.year; + month = cal.month; + day = cal.day; + hour = cal.hour; + minute = cal.minutes; + second = cal.seconds; + + tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + } + +/* +* Create an X509_Time +*/ +X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t) + { + set_to(t_spec, tag); + } + +/* +* Set the time with a human readable string +*/ +void X509_Time::set_to(const std::string& time_str) + { + if(time_str == "") + { + year = month = day = hour = minute = second = 0; + tag = NO_OBJECT; + return; + } + + std::vector params; + std::string current; + + for(size_t j = 0; j != time_str.size(); ++j) + { + if(Charset::is_digit(time_str[j])) + current += time_str[j]; + else + { + if(current != "") + params.push_back(current); + current.clear(); + } + } + if(current != "") + params.push_back(current); + + if(params.size() < 3 || params.size() > 6) + throw Invalid_Argument("Invalid time specification " + time_str); + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + hour = (params.size() >= 4) ? to_u32bit(params[3]) : 0; + minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0; + second = (params.size() == 6) ? to_u32bit(params[5]) : 0; + + tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + time_str); + } + +/* +* Set the time with an ISO time format string +*/ +void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) + { + if(spec_tag != GENERALIZED_TIME && spec_tag != UTC_TIME) + throw Invalid_Argument("X509_Time: Invalid tag " + to_string(spec_tag)); + + if(spec_tag == GENERALIZED_TIME && t_spec.size() != 13 && t_spec.size() != 15) + throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec); + + if(spec_tag == UTC_TIME && t_spec.size() != 11 && t_spec.size() != 13) + throw Invalid_Argument("Invalid UTCTime: " + t_spec); + + if(t_spec[t_spec.size()-1] != 'Z') + throw Invalid_Argument("Invalid time encoding: " + t_spec); + + const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; + + std::vector params; + std::string current; + + for(size_t j = 0; j != YEAR_SIZE; ++j) + current += t_spec[j]; + params.push_back(current); + current.clear(); + + for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) + { + current += t_spec[j]; + if(current.size() == 2) + { + params.push_back(current); + current.clear(); + } + } + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + hour = to_u32bit(params[3]); + minute = to_u32bit(params[4]); + second = (params.size() == 6) ? to_u32bit(params[5]) : 0; + tag = spec_tag; + + if(spec_tag == UTC_TIME) + { + if(year >= 50) year += 1900; + else year += 2000; + } + + if(!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + t_spec); + } + +/* +* DER encode a X509_Time +*/ +void X509_Time::encode_into(DER_Encoder& der) const + { + if(tag != GENERALIZED_TIME && tag != UTC_TIME) + throw Invalid_Argument("X509_Time: Bad encoding tag"); + + der.add_object(tag, UNIVERSAL, + Charset::transcode(as_string(), + LOCAL_CHARSET, + LATIN1_CHARSET)); + } + +/* +* Decode a BER encoded X509_Time +*/ +void X509_Time::decode_from(BER_Decoder& source) + { + BER_Object ber_time = source.get_next_object(); + + set_to(Charset::transcode(ASN1::to_string(ber_time), + LATIN1_CHARSET, + LOCAL_CHARSET), + ber_time.type_tag); + } + +/* +* Return a string representation of the time +*/ +std::string X509_Time::as_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::as_string: No time set"); + + std::string asn1rep; + if(tag == GENERALIZED_TIME) + asn1rep = to_string(year, 4); + else if(tag == UTC_TIME) + { + if(year < 1950 || year >= 2050) + throw Encoding_Error("X509_Time: The time " + readable_string() + + " cannot be encoded as a UTCTime"); + u32bit asn1year = (year >= 2000) ? (year - 2000) : (year - 1900); + asn1rep = to_string(asn1year, 2); + } + else + throw Invalid_Argument("X509_Time: Invalid tag " + to_string(tag)); + + asn1rep += to_string(month, 2) + to_string(day, 2); + asn1rep += to_string(hour, 2) + to_string(minute, 2) + to_string(second, 2); + asn1rep += "Z"; + return asn1rep; + } + +/* +* Return if the time has been set somehow +*/ +bool X509_Time::time_is_set() const + { + return (year != 0); + } + +/* +* Return a human readable string representation +*/ +std::string X509_Time::readable_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::readable_string: No time set"); + + std::string readable; + readable += to_string(year, 4) + "/"; + readable += to_string(month ) + "/"; + readable += to_string(day ) + " "; + readable += to_string(hour ) + ":"; + readable += to_string(minute, 2) + ":"; + readable += to_string(second, 2) + " UTC"; + return readable; + } + +/* +* Do a general sanity check on the time +*/ +bool X509_Time::passes_sanity_check() const + { + if(year < 1950 || year > 2100) + return false; + if(month == 0 || month > 12) + return false; + if(day == 0 || day > 31) + return false; + if(hour >= 24 || minute > 60 || second > 60) + return false; + return true; + } + +/* +* Compare this time against another +*/ +s32bit X509_Time::cmp(const X509_Time& other) const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::cmp: No time set"); + + const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0; + + if(year < other.year) return EARLIER; + if(year > other.year) return LATER; + if(month < other.month) return EARLIER; + if(month > other.month) return LATER; + if(day < other.day) return EARLIER; + if(day > other.day) return LATER; + if(hour < other.hour) return EARLIER; + if(hour > other.hour) return LATER; + if(minute < other.minute) return EARLIER; + if(minute > other.minute) return LATER; + if(second < other.second) return EARLIER; + if(second > other.second) return LATER; + + return SAME_TIME; + } + +/* +* Compare two X509_Times for in various ways +*/ +bool operator==(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) == 0); } +bool operator!=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) != 0); } + +bool operator<=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) <= 0); } +bool operator>=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) >= 0); } + +bool operator<(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) < 0); } +bool operator>(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) > 0); } + +} +/* +* BER Decoder +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* BER decode an ASN.1 type tag +*/ +size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag) + { + byte b; + if(!ber->read_byte(b)) + { + class_tag = type_tag = NO_OBJECT; + return 0; + } + + if((b & 0x1F) != 0x1F) + { + type_tag = ASN1_Tag(b & 0x1F); + class_tag = ASN1_Tag(b & 0xE0); + return 1; + } + + size_t tag_bytes = 1; + class_tag = ASN1_Tag(b & 0xE0); + + size_t tag_buf = 0; + while(true) + { + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Long-form tag truncated"); + if(tag_buf & 0xFF000000) + throw BER_Decoding_Error("Long-form tag overflowed 32 bits"); + ++tag_bytes; + tag_buf = (tag_buf << 7) | (b & 0x7F); + if((b & 0x80) == 0) break; + } + type_tag = ASN1_Tag(tag_buf); + return tag_bytes; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource*); + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber, size_t& field_size) + { + byte b; + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Length field not found"); + field_size = 1; + if((b & 0x80) == 0) + return b; + + field_size += (b & 0x7F); + if(field_size == 1) return find_eoc(ber); + if(field_size > 5) + throw BER_Decoding_Error("Length field is too large"); + + size_t length = 0; + + for(size_t i = 0; i != field_size - 1; ++i) + { + if(get_byte(0, length) != 0) + throw BER_Decoding_Error("Field length overflow"); + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Corrupted length field"); + length = (length << 8) | b; + } + return length; + } + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber) + { + size_t dummy; + return decode_length(ber, dummy); + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* ber) + { + SecureVector buffer(DEFAULT_BUFFERSIZE), data; + + while(true) + { + const size_t got = ber->peek(&buffer[0], buffer.size(), data.size()); + if(got == 0) + break; + + data += std::make_pair(&buffer[0], got); + } + + DataSource_Memory source(data); + data.clear(); + + size_t length = 0; + while(true) + { + ASN1_Tag type_tag, class_tag; + size_t tag_size = decode_tag(&source, type_tag, class_tag); + if(type_tag == NO_OBJECT) + break; + + size_t length_size = 0; + size_t item_size = decode_length(&source, length_size); + source.discard_next(item_size); + + length += item_size + length_size + tag_size; + + if(type_tag == EOC) + break; + } + return length; + } + +} + +/* +* Check a type invariant on BER data +*/ +void BER_Object::assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(this->type_tag != type_tag || this->class_tag != class_tag) + throw BER_Decoding_Error("Tag mismatch when decoding"); + } + +/* +* Check if more objects are there +*/ +bool BER_Decoder::more_items() const + { + if(source->end_of_data() && (pushed.type_tag == NO_OBJECT)) + return false; + return true; + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end() + { + if(!source->end_of_data() || (pushed.type_tag != NO_OBJECT)) + throw Invalid_State("BER_Decoder::verify_end called, but data remains"); + return (*this); + } + +/* +* Save all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::raw_bytes(MemoryRegion& out) + { + out.clear(); + byte buf; + while(source->read_byte(buf)) + out.push_back(buf); + return (*this); + } + +/* +* Discard all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::discard_remaining() + { + byte buf; + while(source->read_byte(buf)) + ; + return (*this); + } + +/* +* Return the BER encoding of the next object +*/ +BER_Object BER_Decoder::get_next_object() + { + BER_Object next; + + if(pushed.type_tag != NO_OBJECT) + { + next = pushed; + pushed.class_tag = pushed.type_tag = NO_OBJECT; + return next; + } + + decode_tag(source, next.type_tag, next.class_tag); + if(next.type_tag == NO_OBJECT) + return next; + + size_t length = decode_length(source); + next.value.resize(length); + if(source->read(&next.value[0], length) != length) + throw BER_Decoding_Error("Value truncated"); + + if(next.type_tag == EOC && next.class_tag == UNIVERSAL) + return get_next_object(); + + return next; + } + +/* +* Push a object back into the stream +*/ +void BER_Decoder::push_back(const BER_Object& obj) + { + if(pushed.type_tag != NO_OBJECT) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + pushed = obj; + } + +/* +* Begin decoding a CONSTRUCTED type +*/ +BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + + BER_Decoder result(&obj.value[0], obj.value.size()); + result.parent = this; + return result; + } + +/* +* Finish decoding a CONSTRUCTED type +*/ +BER_Decoder& BER_Decoder::end_cons() + { + if(!parent) + throw Invalid_State("BER_Decoder::end_cons called with NULL parent"); + if(!source->end_of_data()) + throw Decoding_Error("BER_Decoder::end_cons called with data left"); + return (*parent); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(DataSource& src) + { + source = &src; + owns = false; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = 0; + } + +/* +* BER_Decoder Constructor + */ +BER_Decoder::BER_Decoder(const byte data[], size_t length) + { + source = new DataSource_Memory(data, length); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = 0; + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const MemoryRegion& data) + { + source = new DataSource_Memory(data); + owns = true; + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = 0; + } + +/* +* BER_Decoder Copy Constructor +*/ +BER_Decoder::BER_Decoder(const BER_Decoder& other) + { + source = other.source; + owns = false; + if(other.owns) + { + other.owns = false; + owns = true; + } + pushed.type_tag = pushed.class_tag = NO_OBJECT; + parent = other.parent; + } + +/* +* BER_Decoder Destructor +*/ +BER_Decoder::~BER_Decoder() + { + if(owns) + delete source; + source = 0; + } + +/* +* Request for an object to decode itself +*/ +BER_Decoder& BER_Decoder::decode(ASN1_Object& obj) + { + obj.decode_from(*this); + return (*this); + } + +/* +* Decode a BER encoded NULL +*/ +BER_Decoder& BER_Decoder::decode_null() + { + BER_Object obj = get_next_object(); + obj.assert_is_a(NULL_TAG, UNIVERSAL); + if(obj.value.size()) + throw BER_Decoding_Error("NULL object had nonzero size"); + return (*this); + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out) + { + return decode(out, BOOLEAN, UNIVERSAL); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) + { + SecureVector out_vec; + decode(out_vec, OCTET_STRING); + out = BigInt::decode(&out_vec[0], out_vec.size()); + return (*this); + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.value.size() != 1) + throw BER_Decoding_Error("BER boolean value had invalid size"); + + out = (obj.value[0]) ? true : false; + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.bits() > 32) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | integer.byte_at(3-i); + + return (*this); + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.value.empty()) + out = 0; + else + { + const bool negative = (obj.value[0] & 0x80) ? true : false; + + if(negative) + { + for(size_t i = obj.value.size(); i > 0; --i) + if(obj.value[i-1]--) + break; + for(size_t i = 0; i != obj.value.size(); ++i) + obj.value[i] = ~obj.value[i]; + } + + out = BigInt(&obj.value[0], obj.value.size()); + + if(negative) + out.flip_sign(); + } + + return (*this); + } + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(MemoryRegion& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(MemoryRegion& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(real_type == OCTET_STRING) + buffer = obj.value; + else + { + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + + buffer.resize(obj.value.size() - 1); + copy_mem(&buffer[0], &obj.value[1], obj.value.size() - 1); + } + return (*this); + } + +/* +* Decode an OPTIONAL string type +*/ +BER_Decoder& BER_Decoder::decode_optional_string(MemoryRegion& out, + ASN1_Tag real_type, + u16bit type_no) + { + BER_Object obj = get_next_object(); + + ASN1_Tag type_tag = static_cast(type_no); + + out.clear(); + push_back(obj); + + if(obj.type_tag == type_tag && obj.class_tag == CONTEXT_SPECIFIC) + decode(out, real_type, type_tag, CONTEXT_SPECIFIC); + + return (*this); + } + +} +/* +* DER Encoder +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* DER encode an ASN.1 type tag +*/ +SecureVector encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if((class_tag | 0xE0) != 0xE0) + throw Encoding_Error("DER_Encoder: Invalid class tag " + + to_string(class_tag)); + + SecureVector encoded_tag; + if(type_tag <= 30) + encoded_tag.push_back(static_cast(type_tag | class_tag)); + else + { + size_t blocks = high_bit(type_tag) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + encoded_tag.push_back(class_tag | 0x1F); + for(size_t i = 0; i != blocks - 1; ++i) + encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F)); + encoded_tag.push_back(type_tag & 0x7F); + } + + return encoded_tag; + } + +/* +* DER encode an ASN.1 length field +*/ +SecureVector encode_length(size_t length) + { + SecureVector encoded_length; + if(length <= 127) + encoded_length.push_back(static_cast(length)); + else + { + const size_t top_byte = significant_bytes(length); + + encoded_length.push_back(static_cast(0x80 | top_byte)); + + for(size_t i = sizeof(length) - top_byte; i != sizeof(length); ++i) + encoded_length.push_back(get_byte(i, length)); + } + return encoded_length; + } + +} + +/* +* Return the encoded SEQUENCE/SET +*/ +SecureVector DER_Encoder::DER_Sequence::get_contents() + { + const ASN1_Tag real_class_tag = ASN1_Tag(class_tag | CONSTRUCTED); + + if(type_tag == SET) + { + std::sort(set_contents.begin(), set_contents.end()); + for(size_t i = 0; i != set_contents.size(); ++i) + contents += set_contents[i]; + set_contents.clear(); + } + + SecureVector result; + result += encode_tag(type_tag, real_class_tag); + result += encode_length(contents.size()); + result += contents; + contents.clear(); + + return result; + } + +/* +* Add an encoded value to the SEQUENCE/SET +*/ +void DER_Encoder::DER_Sequence::add_bytes(const byte data[], size_t length) + { + if(type_tag == SET) + set_contents.push_back(SecureVector(data, length)); + else + contents += std::make_pair(data, length); + } + +/* +* Return the type and class taggings +*/ +ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const + { + return ASN1_Tag(type_tag | class_tag); + } + +/* +* DER_Sequence Constructor +*/ +DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : + type_tag(t1), class_tag(t2) + { + } + +/* +* Return the encoded contents +*/ +SecureVector DER_Encoder::get_contents() + { + if(subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + SecureVector output; + std::swap(output, contents); + return output; + } + +/* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + subsequences.push_back(DER_Sequence(type_tag, class_tag)); + return (*this); + } + +/* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::end_cons() + { + if(subsequences.empty()) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + + SecureVector seq = subsequences[subsequences.size()-1].get_contents(); + subsequences.pop_back(); + raw_bytes(seq); + return (*this); + } + +/* +* Start a new ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::start_explicit(u16bit type_no) + { + ASN1_Tag type_tag = static_cast(type_no); + + if(type_tag == SET) + throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform"); + + return start_cons(type_tag, CONTEXT_SPECIFIC); + } + +/* +* Finish the current ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::end_explicit() + { + return end_cons(); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const MemoryRegion& val) + { + return raw_bytes(&val[0], val.size()); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const byte bytes[], size_t length) + { + if(subsequences.size()) + subsequences[subsequences.size()-1].add_bytes(bytes, length); + else + contents += std::make_pair(bytes, length); + + return (*this); + } + +/* +* Encode a NULL object +*/ +DER_Encoder& DER_Encoder::encode_null() + { + return add_object(NULL_TAG, UNIVERSAL, 0, 0); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true) + { + return encode(is_true, BOOLEAN, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n) + { + return encode(BigInt(n), INTEGER, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n) + { + return encode(n, INTEGER, UNIVERSAL); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const MemoryRegion& bytes, + ASN1_Tag real_type) + { + return encode(&bytes[0], bytes.size(), + real_type, real_type, UNIVERSAL); + } + +/* +* Encode this object +*/ +DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length, + ASN1_Tag real_type) + { + return encode(bytes, length, real_type, real_type, UNIVERSAL); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + byte val = is_true ? 0xFF : 0x00; + return add_object(type_tag, class_tag, &val, 1); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(BigInt(n), type_tag, class_tag); + } + +/* +* DER encode an INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + return add_object(type_tag, class_tag, 0); + + bool extra_zero = (n.bits() % 8 == 0); + SecureVector contents(extra_zero + n.bytes()); + BigInt::encode(&contents[extra_zero], n); + if(n < 0) + { + for(size_t i = 0; i != contents.size(); ++i) + contents[i] = ~contents[i]; + for(size_t i = contents.size(); i > 0; --i) + if(++contents[i-1]) + break; + } + + return add_object(type_tag, class_tag, contents); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const MemoryRegion& bytes, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(&bytes[0], bytes.size(), + real_type, type_tag, class_tag); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const byte bytes[], size_t length, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); + + if(real_type == BIT_STRING) + { + SecureVector encoded; + encoded.push_back(0); + encoded += std::make_pair(bytes, length); + return add_object(type_tag, class_tag, encoded); + } + else + return add_object(type_tag, class_tag, bytes, length); + } + +/* +* Conditionally write some values to the stream +*/ +DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec) + { + if(cond) + return raw_bytes(codec.get_contents()); + return (*this); + } + +/* +* Request for an object to encode itself +*/ +DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) + { + obj.encode_into(*this); + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const byte rep[], size_t length) + { + SecureVector buffer; + buffer += encode_tag(type_tag, class_tag); + buffer += encode_length(length); + buffer += std::make_pair(rep, length); + + return raw_bytes(buffer); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const MemoryRegion& rep_buf) + { + const byte* rep = &rep_buf[0]; + const size_t rep_len = rep_buf.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& rep_str) + { + const byte* rep = reinterpret_cast(rep_str.data()); + const size_t rep_len = rep_str.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, + ASN1_Tag class_tag, byte rep) + { + return add_object(type_tag, class_tag, &rep, 1); + } + +} +/* +* X509_DN +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create an empty X509_DN +*/ +X509_DN::X509_DN() + { + } + +/* +* Create an X509_DN +*/ +X509_DN::X509_DN(const std::multimap& args) + { + std::multimap::const_iterator j; + for(j = args.begin(); j != args.end(); ++j) + add_attribute(j->first, j->second); + } + +/* +* Create an X509_DN +*/ +X509_DN::X509_DN(const std::multimap& args) + { + std::multimap::const_iterator j; + for(j = args.begin(); j != args.end(); ++j) + add_attribute(OIDS::lookup(j->first), j->second); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const std::string& type, + const std::string& str) + { + OID oid = OIDS::lookup(type); + add_attribute(oid, str); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const OID& oid, const std::string& str) + { + if(str == "") + return; + + typedef std::multimap::iterator rdn_iter; + + std::pair range = dn_info.equal_range(oid); + for(rdn_iter j = range.first; j != range.second; ++j) + if(j->second.value() == str) + return; + + multimap_insert(dn_info, oid, ASN1_String(str)); + dn_bits.clear(); + } + +/* +* Get the attributes of this X509_DN +*/ +std::multimap X509_DN::get_attributes() const + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap retval; + for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j) + multimap_insert(retval, j->first, j->second.value()); + return retval; + } + +/* +* Get the contents of this X.500 Name +*/ +std::multimap X509_DN::contents() const + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap retval; + for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j) + multimap_insert(retval, OIDS::lookup(j->first), j->second.value()); + return retval; + } + +/* +* Get a single attribute type +*/ +std::vector X509_DN::get_attribute(const std::string& attr) const + { + typedef std::multimap::const_iterator rdn_iter; + + const OID oid = OIDS::lookup(deref_info_field(attr)); + std::pair range = dn_info.equal_range(oid); + + std::vector values; + for(rdn_iter j = range.first; j != range.second; ++j) + values.push_back(j->second.value()); + return values; + } + +/* +* Return the BER encoded data, if any +*/ +MemoryVector X509_DN::get_bits() const + { + return dn_bits; + } + +/* +* Deref aliases in a subject/issuer info request +*/ +std::string X509_DN::deref_info_field(const std::string& info) + { + if(info == "Name" || info == "CommonName") return "X520.CommonName"; + if(info == "SerialNumber") return "X520.SerialNumber"; + if(info == "Country") return "X520.Country"; + if(info == "Organization") return "X520.Organization"; + if(info == "Organizational Unit" || info == "OrgUnit") + return "X520.OrganizationalUnit"; + if(info == "Locality") return "X520.Locality"; + if(info == "State" || info == "Province") return "X520.State"; + if(info == "Email") return "RFC822"; + return info; + } + +/* +* Compare two X509_DNs for equality +*/ +bool operator==(const X509_DN& dn1, const X509_DN& dn2) + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap attr1 = dn1.get_attributes(); + std::multimap attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + rdn_iter p1 = attr1.begin(); + rdn_iter p2 = attr2.begin(); + + while(true) + { + if(p1 == attr1.end() && p2 == attr2.end()) + break; + if(p1 == attr1.end()) return false; + if(p2 == attr2.end()) return false; + if(p1->first != p2->first) return false; + if(!x500_name_cmp(p1->second, p2->second)) + return false; + ++p1; + ++p2; + } + return true; + } + +/* +* Compare two X509_DNs for inequality +*/ +bool operator!=(const X509_DN& dn1, const X509_DN& dn2) + { + return !(dn1 == dn2); + } + +/* +* Compare two X509_DNs +*/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + typedef std::multimap::const_iterator rdn_iter; + + std::multimap attr1 = dn1.get_attributes(); + std::multimap attr2 = dn2.get_attributes(); + + if(attr1.size() < attr2.size()) return true; + if(attr1.size() > attr2.size()) return false; + + for(rdn_iter p1 = attr1.begin(); p1 != attr1.end(); ++p1) + { + std::multimap::const_iterator p2; + p2 = attr2.find(p1->first); + if(p2 == attr2.end()) return false; + if(p1->second > p2->second) return false; + if(p1->second < p2->second) return true; + } + return false; + } + +namespace { + +/* +* DER encode a RelativeDistinguishedName +*/ +void do_ava(DER_Encoder& encoder, + const std::multimap& dn_info, + ASN1_Tag string_type, const std::string& oid_str, + bool must_exist = false) + { + typedef std::multimap::const_iterator rdn_iter; + + const OID oid = OIDS::lookup(oid_str); + const bool exists = (dn_info.find(oid) != dn_info.end()); + + if(!exists && must_exist) + throw Encoding_Error("X509_DN: No entry for " + oid_str); + if(!exists) return; + + std::pair range = dn_info.equal_range(oid); + + for(rdn_iter j = range.first; j != range.second; ++j) + { + encoder.start_cons(SET) + .start_cons(SEQUENCE) + .encode(oid) + .encode(ASN1_String(j->second, string_type)) + .end_cons() + .end_cons(); + } + } + +} + +/* +* DER encode a DistinguishedName +*/ +void X509_DN::encode_into(DER_Encoder& der) const + { + std::multimap dn_info = get_attributes(); + + der.start_cons(SEQUENCE); + + if(!dn_bits.empty()) + der.raw_bytes(dn_bits); + else + { + do_ava(der, dn_info, PRINTABLE_STRING, "X520.Country"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.State"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.Locality"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.Organization"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.OrganizationalUnit"); + do_ava(der, dn_info, DIRECTORY_STRING, "X520.CommonName"); + do_ava(der, dn_info, PRINTABLE_STRING, "X520.SerialNumber"); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded DistinguishedName +*/ +void X509_DN::decode_from(BER_Decoder& source) + { + MemoryVector bits; + + source.start_cons(SEQUENCE) + .raw_bytes(bits) + .end_cons(); + + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = sequence.start_cons(SET); + + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + rdn.start_cons(SEQUENCE) + .decode(oid) + .decode(str) + .verify_end() + .end_cons(); + + add_attribute(oid, str.value()); + } + } + + dn_bits = bits; + } + +} +/* +* Runtime benchmarking +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/** +* Benchmark Buffered_Computation (hash or MAC) +*/ +std::pair bench_buf_comp(Buffered_Computation* buf_comp, + u64bit nanoseconds_max, + const byte buf[], size_t buf_len) + { + u64bit reps = 0; + u64bit nanoseconds_used = 0; + + while(nanoseconds_used < nanoseconds_max) + { + const u64bit start = get_nanoseconds_clock(); + buf_comp->update(buf, buf_len); + nanoseconds_used += get_nanoseconds_clock() - start; + + ++reps; + } + + return std::make_pair(reps * buf_len, nanoseconds_used); + } + +/** +* Benchmark block cipher +*/ +std::pair +bench_block_cipher(BlockCipher* block_cipher, + u64bit nanoseconds_max, + byte buf[], size_t buf_len) + { + const size_t in_blocks = buf_len / block_cipher->block_size(); + + u64bit reps = 0; + u64bit nanoseconds_used = 0; + + block_cipher->set_key(buf, block_cipher->maximum_keylength()); + + while(nanoseconds_used < nanoseconds_max) + { + const u64bit start = get_nanoseconds_clock(); + block_cipher->encrypt_n(buf, buf, in_blocks); + nanoseconds_used += get_nanoseconds_clock() - start; + + ++reps; + } + + return std::make_pair(reps * in_blocks * block_cipher->block_size(), + nanoseconds_used); + } + +/** +* Benchmark stream +*/ +std::pair +bench_stream_cipher(StreamCipher* stream_cipher, + u64bit nanoseconds_max, + byte buf[], size_t buf_len) + { + u64bit reps = 0; + u64bit nanoseconds_used = 0; + + stream_cipher->set_key(buf, stream_cipher->maximum_keylength()); + + while(nanoseconds_used < nanoseconds_max) + { + const u64bit start = get_nanoseconds_clock(); + stream_cipher->cipher1(buf, buf_len); + nanoseconds_used += get_nanoseconds_clock() - start; + + ++reps; + } + + return std::make_pair(reps * buf_len, nanoseconds_used); + } + +/** +* Benchmark hash +*/ +std::pair +bench_hash(HashFunction* hash, + u64bit nanoseconds_max, + const byte buf[], size_t buf_len) + { + return bench_buf_comp(hash, nanoseconds_max, buf, buf_len); + } + +/** +* Benchmark MAC +*/ +std::pair +bench_mac(MessageAuthenticationCode* mac, + u64bit nanoseconds_max, + const byte buf[], size_t buf_len) + { + mac->set_key(buf, mac->maximum_keylength()); + return bench_buf_comp(mac, nanoseconds_max, buf, buf_len); + } + +} + +std::map +algorithm_benchmark(const std::string& name, + Algorithm_Factory& af, + RandomNumberGenerator& rng, + u32bit milliseconds, + size_t buf_size) + { + std::vector providers = af.providers_of(name); + std::map all_results; + + if(providers.empty()) // no providers, nothing to do + return all_results; + + const u64bit ns_per_provider = + (static_cast(milliseconds) * 1000 * 1000) / providers.size(); + + std::vector buf(buf_size * 1024); + rng.randomize(&buf[0], buf.size()); + + for(size_t i = 0; i != providers.size(); ++i) + { + const std::string provider = providers[i]; + + std::pair results(0, 0); + + if(const BlockCipher* proto = + af.prototype_block_cipher(name, provider)) + { + std::unique_ptr block_cipher(proto->clone()); + results = bench_block_cipher(block_cipher.get(), + ns_per_provider, + &buf[0], buf.size()); + } + else if(const StreamCipher* proto = + af.prototype_stream_cipher(name, provider)) + { + std::unique_ptr stream_cipher(proto->clone()); + results = bench_stream_cipher(stream_cipher.get(), + ns_per_provider, + &buf[0], buf.size()); + } + else if(const HashFunction* proto = + af.prototype_hash_function(name, provider)) + { + std::unique_ptr hash(proto->clone()); + results = bench_hash(hash.get(), ns_per_provider, + &buf[0], buf.size()); + } + else if(const MessageAuthenticationCode* proto = + af.prototype_mac(name, provider)) + { + std::unique_ptr mac(proto->clone()); + results = bench_mac(mac.get(), ns_per_provider, + &buf[0], buf.size()); + } + + if(results.first && results.second) + { + /* 953.67 == 1000 * 1000 * 1000 / 1024 / 1024 - the conversion + factor from bytes per nanosecond to mebibytes per second. + */ + double speed = (953.67 * results.first) / results.second; + all_results[provider] = speed; + } + } + + return all_results; + } + +} +/* +* AES +* (C) 1999-2010 Jack Lloyd +* +* Based on the public domain reference implemenation +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +const byte SE[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 }; + +const byte SD[256] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D }; + +const u32bit TE[1024] = { + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, + 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, + 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D, + 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, + 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, + 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4, + 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, + 0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, + 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E, + 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, + 0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, + 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46, + 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, + 0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, + 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE, + 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, + 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, + 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2, + 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, + 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, + 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256, + 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, + 0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, + 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA, + 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, + 0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, + 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42, + 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, + 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, + 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22, + 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, + 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, + 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, 0xA5C66363, 0x84F87C7C, + 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, + 0xE64DABAB, 0x9AEC7676, 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, + 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, 0xEC41ADAD, 0x67B3D4D4, + 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, + 0x02F5F7F7, 0x4F83CCCC, 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, + 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, 0x0C080404, 0x5295C7C7, + 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, + 0xCD7FB2B2, 0x9FEA7575, 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, + 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, 0xF6A45252, 0x4D763B3B, + 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, + 0xC879B1B1, 0xEDB65B5B, 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, + 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, 0x6BBBD0D0, 0x2AC5EFEF, + 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, + 0xBA259F9F, 0xE34BA8A8, 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, + 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, 0xDF63BCBC, 0xC177B6B6, + 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, + 0xCC884444, 0x392E1717, 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, + 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, 0xA0C06060, 0x98198181, + 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, + 0x1D160B0B, 0x76ADDBDB, 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, + 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, 0x5D9FC2C2, 0x6EBDD3D3, + 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, + 0xD29C4E4E, 0xE049A9A9, 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, + 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, 0xD56FBABA, 0x88F07878, + 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, + 0x860D8B8B, 0x850F8A8A, 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, + 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, 0xA3C26161, 0x5F6A3535, + 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, + 0x89078E8E, 0xA7339494, 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, + 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, 0x8F038C8C, 0xF859A1A1, + 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, + 0xD66DBBBB, 0x3A2C1616, 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, + 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, 0x30506030, 0x01030201, + 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, + 0x47C98E47, 0xF00BFBF0, 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, + 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, 0xB7C275B7, 0xFD1CE1FD, + 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, + 0x31536231, 0x153F2A15, 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, + 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, 0x07090E07, 0x12362412, + 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, + 0x5AEEB45A, 0xA0FB5BA0, 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, + 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, 0x53F5A653, 0xD168B9D1, + 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, + 0x58E8B058, 0xCF4A85CF, 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, + 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, 0x45CF8A45, 0xF910E9F9, + 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, + 0x38487038, 0xF504F1F5, 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, + 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, 0xCD4C81CD, 0x0C14180C, + 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, + 0x192B3219, 0x7395E673, 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, + 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, 0x46CA8C46, 0xEE29C7EE, + 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, + 0x246C4824, 0x5CE4B85C, 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, + 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, 0xE732D5E7, 0xC8438BC8, + 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, + 0xAEE947AE, 0x08181008, 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, + 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, 0xE823CBE8, 0xDD7CA1DD, + 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, + 0xF601F7F6, 0x0E121C0E, 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, + 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, 0xE138D9E1, 0xF813EBF8, + 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, + 0x28785028, 0xDF7AA5DF, 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, + 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, 0x41C38241, 0x99B02999, + 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, + 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, + 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, + 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, + 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, + 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451, + 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, + 0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, + 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D, + 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, + 0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, + 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, + 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, + 0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, + 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, + 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, + 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, + 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255, + 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, + 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, + 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664, + 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, + 0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, + 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC, + 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, + 0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, + 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, + 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, + 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, + 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, + 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, + 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, + 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C }; + +const u32bit TD[1024] = { + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, + 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, + 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67, + 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, + 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, + 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182, + 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, + 0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, + 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492, + 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, + 0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, + 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997, + 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, + 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, + 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F, + 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, + 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, + 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC, + 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, + 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, + 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1, + 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, + 0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, + 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4, + 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, + 0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, + 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D, + 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, + 0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, + 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F, + 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, + 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, + 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742, 0x5051F4A7, 0x537E4165, + 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, + 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, + 0x80263544, 0x8FB562A3, 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, + 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, 0xE7038F5F, 0x9515929C, + 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, + 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, + 0x66C920AC, 0xB47DCE3A, 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, + 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, 0x58704868, 0x198F45FD, + 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, + 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, + 0xBA02036A, 0x5CED1682, 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, + 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, 0x9D342E53, 0xA0A2F355, + 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, + 0x6F0406D4, 0xFF605015, 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, + 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, 0x47A17C0A, 0xE97C420F, + 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, + 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, + 0xD19B5B54, 0x3A24362E, 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, + 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, 0x0AE293BA, 0xE5C0A02A, + 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, + 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, + 0xC544663B, 0x345BFB7E, 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, + 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, 0x7D854A24, 0xF8D2BB3D, + 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, + 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, + 0xD8567D2C, 0xEF223390, 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, + 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, 0xE42C3A9D, 0x0D507892, + 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, + 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, + 0x6EE89C63, 0x7BDB3BBB, 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, + 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, 0xD9BAE79B, 0xCE4A6F36, + 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, + 0x0E7FCD50, 0x2F1791F6, 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, + 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, 0x049D5EEA, 0x5D018C35, + 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, + 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, + 0xEDE11CE5, 0x3C7A47B1, 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, + 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, 0x81CAAFF3, 0x3EB968C4, + 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, + 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, + 0x74486C5C, 0x42D0B857, 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, + 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, 0xFA552030, 0x6DF6AD76, + 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, + 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, + 0x97A38D46, 0xF9C66BD3, 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, + 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, 0x896A75C2, 0x7978F48E, + 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, + 0xA01CFE81, 0x2B94F908, 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, + 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, 0x2807B2EB, 0xC2032FB5, + 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, + 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, + 0x621FD134, 0xFE8AC4A6, 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, + 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, 0x8AF93E21, 0x063D96DD, + 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, + 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, + 0x5B38E719, 0xEEDB79C8, 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, + 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, 0xFFFBFD0E, 0x38560F85, + 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, + 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, + 0x4B695A77, 0x1A161C12, 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, + 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, 0x198557F1, 0x074CAF75, + 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, + 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, + 0x22401397, 0x112084C6, 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, + 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, 0x166C2BB3, 0xB999A970, + 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, + 0x8E26DAB7, 0xBFA43FAD, 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, + 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, 0x80BE9F5D, 0x937C69D0, + 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, + 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, + 0xCF0821BC, 0xE8E6EF15, 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, + 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, 0xBC37744E, 0xCAA6FC82, + 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, + 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, + 0x1FB8C12C, 0x517F4665, 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, + 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, 0x618C9AD7, 0x0C7A37A1, + 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, + 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, + 0x6F14DF3D, 0xDB867844, 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, + 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, 0x017139A8, 0xB3DE080C, + 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8, + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, + 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, + 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, + 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, + 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, + 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5, + 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, + 0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, + 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7, + 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, + 0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, + 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, + 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, + 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, + 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, + 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, + 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, + 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB, + 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, + 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, + 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9, + 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, + 0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, + 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E, + 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, + 0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, + 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, + 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, + 0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, + 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, + 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, + 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, + 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 }; + +/* +* AES Encryption +*/ +void aes_encrypt_n(const byte in[], byte out[], + size_t blocks, + const MemoryRegion& EK, + const MemoryRegion& ME) + { + const size_t BLOCK_SIZE = 16; + + const u32bit* TE0 = TE; + const u32bit* TE1 = TE + 256; + const u32bit* TE2 = TE + 512; + const u32bit* TE3 = TE + 768; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit T0 = load_be(in, 0) ^ EK[0]; + u32bit T1 = load_be(in, 1) ^ EK[1]; + u32bit T2 = load_be(in, 2) ^ EK[2]; + u32bit T3 = load_be(in, 3) ^ EK[3]; + + /* Use only the first 256 entries of the TE table and do the + * rotations directly in the code. This reduces the number of + * cache lines potentially used in the first round from 64 to 16 + * (assuming a typical 64 byte cache line), which makes timing + * attacks a little harder; the first round is particularly + * vulnerable. + */ + + u32bit B0 = TE[get_byte(0, T0)] ^ + rotate_right(TE[get_byte(1, T1)], 8) ^ + rotate_right(TE[get_byte(2, T2)], 16) ^ + rotate_right(TE[get_byte(3, T3)], 24) ^ EK[4]; + + u32bit B1 = TE[get_byte(0, T1)] ^ + rotate_right(TE[get_byte(1, T2)], 8) ^ + rotate_right(TE[get_byte(2, T3)], 16) ^ + rotate_right(TE[get_byte(3, T0)], 24) ^ EK[5]; + + u32bit B2 = TE[get_byte(0, T2)] ^ + rotate_right(TE[get_byte(1, T3)], 8) ^ + rotate_right(TE[get_byte(2, T0)], 16) ^ + rotate_right(TE[get_byte(3, T1)], 24) ^ EK[6]; + + u32bit B3 = TE[get_byte(0, T3)] ^ + rotate_right(TE[get_byte(1, T0)], 8) ^ + rotate_right(TE[get_byte(2, T1)], 16) ^ + rotate_right(TE[get_byte(3, T2)], 24) ^ EK[7]; + + for(size_t r = 2*4; r < EK.size(); r += 2*4) + { + T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(1, B1)] ^ + TE2[get_byte(2, B2)] ^ TE3[get_byte(3, B3)] ^ EK[r]; + T1 = TE0[get_byte(0, B1)] ^ TE1[get_byte(1, B2)] ^ + TE2[get_byte(2, B3)] ^ TE3[get_byte(3, B0)] ^ EK[r+1]; + T2 = TE0[get_byte(0, B2)] ^ TE1[get_byte(1, B3)] ^ + TE2[get_byte(2, B0)] ^ TE3[get_byte(3, B1)] ^ EK[r+2]; + T3 = TE0[get_byte(0, B3)] ^ TE1[get_byte(1, B0)] ^ + TE2[get_byte(2, B1)] ^ TE3[get_byte(3, B2)] ^ EK[r+3]; + + B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(1, T1)] ^ + TE2[get_byte(2, T2)] ^ TE3[get_byte(3, T3)] ^ EK[r+4]; + B1 = TE0[get_byte(0, T1)] ^ TE1[get_byte(1, T2)] ^ + TE2[get_byte(2, T3)] ^ TE3[get_byte(3, T0)] ^ EK[r+5]; + B2 = TE0[get_byte(0, T2)] ^ TE1[get_byte(1, T3)] ^ + TE2[get_byte(2, T0)] ^ TE3[get_byte(3, T1)] ^ EK[r+6]; + B3 = TE0[get_byte(0, T3)] ^ TE1[get_byte(1, T0)] ^ + TE2[get_byte(2, T1)] ^ TE3[get_byte(3, T2)] ^ EK[r+7]; + } + + /* + Joseph Bonneau and Ilya Mironov's paper "Cache-Collision Timing + Attacks Against AES" describes an attack that can recover AES + keys with as few as 2**13 samples. + + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753 + + They recommend using a byte-wide table, which still allows an attack + but increases the samples required from 2**13 to 2**25: + + """In addition to OpenSSL v. 0.9.8.(a), which was used in our + experiments, the AES implementations of Crypto++ 5.2.1 and + LibTomCrypt 1.09 use the original Rijndael C implementation with + very few changes and are highly vulnerable. The AES implementations + in libgcrypt v. 1.2.2 and Botan v. 1.4.2 are also vulnerable, but + use a smaller byte-wide final table which lessens the effectiveness + of the attacks.""" + */ + + out[ 0] = SE[get_byte(0, B0)] ^ ME[0]; + out[ 1] = SE[get_byte(1, B1)] ^ ME[1]; + out[ 2] = SE[get_byte(2, B2)] ^ ME[2]; + out[ 3] = SE[get_byte(3, B3)] ^ ME[3]; + out[ 4] = SE[get_byte(0, B1)] ^ ME[4]; + out[ 5] = SE[get_byte(1, B2)] ^ ME[5]; + out[ 6] = SE[get_byte(2, B3)] ^ ME[6]; + out[ 7] = SE[get_byte(3, B0)] ^ ME[7]; + out[ 8] = SE[get_byte(0, B2)] ^ ME[8]; + out[ 9] = SE[get_byte(1, B3)] ^ ME[9]; + out[10] = SE[get_byte(2, B0)] ^ ME[10]; + out[11] = SE[get_byte(3, B1)] ^ ME[11]; + out[12] = SE[get_byte(0, B3)] ^ ME[12]; + out[13] = SE[get_byte(1, B0)] ^ ME[13]; + out[14] = SE[get_byte(2, B1)] ^ ME[14]; + out[15] = SE[get_byte(3, B2)] ^ ME[15]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* AES Decryption +*/ +void aes_decrypt_n(const byte in[], byte out[], size_t blocks, + const MemoryRegion& DK, + const MemoryRegion& MD) + { + const size_t BLOCK_SIZE = 16; + + const u32bit* TD0 = TD; + const u32bit* TD1 = TD + 256; + const u32bit* TD2 = TD + 512; + const u32bit* TD3 = TD + 768; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit T0 = load_be(in, 0) ^ DK[0]; + u32bit T1 = load_be(in, 1) ^ DK[1]; + u32bit T2 = load_be(in, 2) ^ DK[2]; + u32bit T3 = load_be(in, 3) ^ DK[3]; + + u32bit B0 = TD[get_byte(0, T0)] ^ + rotate_right(TD[get_byte(1, T3)], 8) ^ + rotate_right(TD[get_byte(2, T2)], 16) ^ + rotate_right(TD[get_byte(3, T1)], 24) ^ DK[4]; + + u32bit B1 = TD[get_byte(0, T1)] ^ + rotate_right(TD[get_byte(1, T0)], 8) ^ + rotate_right(TD[get_byte(2, T3)], 16) ^ + rotate_right(TD[get_byte(3, T2)], 24) ^ DK[5]; + + u32bit B2 = TD[get_byte(0, T2)] ^ + rotate_right(TD[get_byte(1, T1)], 8) ^ + rotate_right(TD[get_byte(2, T0)], 16) ^ + rotate_right(TD[get_byte(3, T3)], 24) ^ DK[6]; + + u32bit B3 = TD[get_byte(0, T3)] ^ + rotate_right(TD[get_byte(1, T2)], 8) ^ + rotate_right(TD[get_byte(2, T1)], 16) ^ + rotate_right(TD[get_byte(3, T0)], 24) ^ DK[7]; + + for(size_t r = 2*4; r < DK.size(); r += 2*4) + { + T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(1, B3)] ^ + TD2[get_byte(2, B2)] ^ TD3[get_byte(3, B1)] ^ DK[r]; + T1 = TD0[get_byte(0, B1)] ^ TD1[get_byte(1, B0)] ^ + TD2[get_byte(2, B3)] ^ TD3[get_byte(3, B2)] ^ DK[r+1]; + T2 = TD0[get_byte(0, B2)] ^ TD1[get_byte(1, B1)] ^ + TD2[get_byte(2, B0)] ^ TD3[get_byte(3, B3)] ^ DK[r+2]; + T3 = TD0[get_byte(0, B3)] ^ TD1[get_byte(1, B2)] ^ + TD2[get_byte(2, B1)] ^ TD3[get_byte(3, B0)] ^ DK[r+3]; + + B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(1, T3)] ^ + TD2[get_byte(2, T2)] ^ TD3[get_byte(3, T1)] ^ DK[r+4]; + B1 = TD0[get_byte(0, T1)] ^ TD1[get_byte(1, T0)] ^ + TD2[get_byte(2, T3)] ^ TD3[get_byte(3, T2)] ^ DK[r+5]; + B2 = TD0[get_byte(0, T2)] ^ TD1[get_byte(1, T1)] ^ + TD2[get_byte(2, T0)] ^ TD3[get_byte(3, T3)] ^ DK[r+6]; + B3 = TD0[get_byte(0, T3)] ^ TD1[get_byte(1, T2)] ^ + TD2[get_byte(2, T1)] ^ TD3[get_byte(3, T0)] ^ DK[r+7]; + } + + out[ 0] = SD[get_byte(0, B0)] ^ MD[0]; + out[ 1] = SD[get_byte(1, B3)] ^ MD[1]; + out[ 2] = SD[get_byte(2, B2)] ^ MD[2]; + out[ 3] = SD[get_byte(3, B1)] ^ MD[3]; + out[ 4] = SD[get_byte(0, B1)] ^ MD[4]; + out[ 5] = SD[get_byte(1, B0)] ^ MD[5]; + out[ 6] = SD[get_byte(2, B3)] ^ MD[6]; + out[ 7] = SD[get_byte(3, B2)] ^ MD[7]; + out[ 8] = SD[get_byte(0, B2)] ^ MD[8]; + out[ 9] = SD[get_byte(1, B1)] ^ MD[9]; + out[10] = SD[get_byte(2, B0)] ^ MD[10]; + out[11] = SD[get_byte(3, B3)] ^ MD[11]; + out[12] = SD[get_byte(0, B3)] ^ MD[12]; + out[13] = SD[get_byte(1, B2)] ^ MD[13]; + out[14] = SD[get_byte(2, B1)] ^ MD[14]; + out[15] = SD[get_byte(3, B0)] ^ MD[15]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +void aes_key_schedule(const byte key[], size_t length, + MemoryRegion& EK, + MemoryRegion& DK, + MemoryRegion& ME, + MemoryRegion& MD) + { + static const u32bit RC[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + + const size_t rounds = (length / 4) + 6; + + SecureVector XEK(length + 32), XDK(length + 32); + + const size_t X = length / 4; + for(size_t i = 0; i != X; ++i) + XEK[i] = load_be(key, i); + + for(size_t i = X; i < 4*(rounds+1); i += X) + { + XEK[i] = XEK[i-X] ^ RC[(i-X)/X] ^ + make_u32bit(SE[get_byte(1, XEK[i-1])], + SE[get_byte(2, XEK[i-1])], + SE[get_byte(3, XEK[i-1])], + SE[get_byte(0, XEK[i-1])]); + + for(size_t j = 1; j != X; ++j) + { + XEK[i+j] = XEK[i+j-X]; + + if(X == 8 && j == 4) + XEK[i+j] ^= make_u32bit(SE[get_byte(0, XEK[i+j-1])], + SE[get_byte(1, XEK[i+j-1])], + SE[get_byte(2, XEK[i+j-1])], + SE[get_byte(3, XEK[i+j-1])]); + else + XEK[i+j] ^= XEK[i+j-1]; + } + } + + for(size_t i = 0; i != 4*(rounds+1); i += 4) + { + XDK[i ] = XEK[4*rounds-i ]; + XDK[i+1] = XEK[4*rounds-i+1]; + XDK[i+2] = XEK[4*rounds-i+2]; + XDK[i+3] = XEK[4*rounds-i+3]; + } + + for(size_t i = 4; i != length + 24; ++i) + XDK[i] = TD[SE[get_byte(0, XDK[i])] + 0] ^ + TD[SE[get_byte(1, XDK[i])] + 256] ^ + TD[SE[get_byte(2, XDK[i])] + 512] ^ + TD[SE[get_byte(3, XDK[i])] + 768]; + + for(size_t i = 0; i != 4; ++i) + { + store_be(XEK[i+4*rounds], &ME[4*i]); + store_be(XEK[i], &MD[4*i]); + } + + EK.resize(length + 24); + DK.resize(length + 24); + copy_mem(&EK[0], &XEK[0], EK.size()); + copy_mem(&DK[0], &XDK[0], DK.size()); + } + +} + +void AES_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_128::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_128::clear() + { + zeroise(EK); + zeroise(DK); + zeroise(ME); + zeroise(MD); + } + +void AES_192::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_192::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_192::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_192::clear() + { + zeroise(EK); + zeroise(DK); + zeroise(ME); + zeroise(MD); + } + +void AES_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_encrypt_n(in, out, blocks, EK, ME); + } + +void AES_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + aes_decrypt_n(in, out, blocks, DK, MD); + } + +void AES_256::key_schedule(const byte key[], size_t length) + { + aes_key_schedule(key, length, EK, DK, ME, MD); + } + +void AES_256::clear() + { + zeroise(EK); + zeroise(DK); + zeroise(ME); + zeroise(MD); + } + +} +/* +* S-Box and P-Box Tables for Blowfish +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u32bit Blowfish::P_INIT[18] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B }; + +const u32bit Blowfish::S_INIT[1024] = { + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, + 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, + 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, + 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, + 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, + 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, + 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, + 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, + 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, + 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, + 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, + 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, + 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, + 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, + 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, + 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, + 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, + 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, + 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, + 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, + 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, + 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, 0x4B7A70E9, 0xB5B32944, + 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, + 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, + 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, + 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, + 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, + 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, + 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, + 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, + 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, + 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, + 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, + 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, + 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, + 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, + 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, + 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, + 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, + 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, + 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, + 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, + 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, + 0xE6E39F2B, 0xDB83ADF7, 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, + 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, + 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, + 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, + 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, + 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, + 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, + 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, + 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, + 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, + 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, + 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, + 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, + 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, + 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, + 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, + 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, + 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, + 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, + 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, + 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, + 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, + 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, + 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, + 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, + 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, + 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, + 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, + 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, + 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, + 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, + 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, + 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, + 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, + 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, + 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, + 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, + 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, + 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, + 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, + 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, + 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, + 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }; + +} +/* +* Blowfish +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Blowfish Encryption +*/ +void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[16]; R ^= P[17]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Decryption +*/ +void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 17; j != 1; j -= 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j-1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[1]; R ^= P[0]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Key Schedule +*/ +void Blowfish::key_schedule(const byte key[], size_t length) + { + clear(); + + const byte null_salt[16] = { 0 }; + + key_expansion(key, length, null_salt); + } + +void Blowfish::key_expansion(const byte key[], + size_t length, + const byte salt[16]) + { + for(size_t i = 0, j = 0; i != 18; ++i, j += 4) + P[i] ^= make_u32bit(key[(j ) % length], key[(j+1) % length], + key[(j+2) % length], key[(j+3) % length]); + + u32bit L = 0, R = 0; + generate_sbox(P, L, R, salt, 0); + generate_sbox(S, L, R, salt, 2); + } + +/* +* Modified key schedule used for bcrypt password hashing +*/ +void Blowfish::eks_key_schedule(const byte key[], size_t length, + const byte salt[16], size_t workfactor) + { + if(length == 0 || length >= 56) + throw Invalid_Key_Length("EKSBlowfish", length); + + if(workfactor == 0) + throw std::invalid_argument("Bcrypt work factor must be at least 1"); + + /* + * On a 2.8 GHz Core-i7, workfactor == 18 takes about 25 seconds to + * hash a password. This seems like a reasonable upper bound for the + * time being. + */ + if(workfactor > 18) + throw std::invalid_argument("Requested Bcrypt work factor too large"); + + clear(); + + const byte null_salt[16] = { 0 }; + + key_expansion(key, length, salt); + + const size_t rounds = 1 << workfactor; + + for(size_t r = 0; r != rounds; ++r) + { + key_expansion(key, length, null_salt); + key_expansion(salt, 16, null_salt); + } + } + +/* +* Generate one of the Sboxes +*/ +void Blowfish::generate_sbox(MemoryRegion& box, + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != box.size(); i += 2) + { + L ^= load_be(salt, (i + salt_off) % 4); + R ^= load_be(salt, (i + salt_off + 1) % 4); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + u32bit T = R; R = L ^ P[16]; L = T ^ P[17]; + box[i] = L; + box[i+1] = R; + } + } + +/* +* Clear memory of sensitive data +*/ +void Blowfish::clear() + { + std::copy(P_INIT, P_INIT + 18, P.begin()); + std::copy(S_INIT, S_INIT + 1024, S.begin()); + } + +} +/* +* Camellia +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace Camellia_F { + +namespace { + +/* +* We use the slow byte-wise version of F in the first and last rounds +* to help protect against timing attacks +*/ +u64bit F_SLOW(u64bit v, u64bit K) + { + static const byte SBOX[256] = { + 0x70, 0x82, 0x2C, 0xEC, 0xB3, 0x27, 0xC0, 0xE5, 0xE4, 0x85, 0x57, + 0x35, 0xEA, 0x0C, 0xAE, 0x41, 0x23, 0xEF, 0x6B, 0x93, 0x45, 0x19, + 0xA5, 0x21, 0xED, 0x0E, 0x4F, 0x4E, 0x1D, 0x65, 0x92, 0xBD, 0x86, + 0xB8, 0xAF, 0x8F, 0x7C, 0xEB, 0x1F, 0xCE, 0x3E, 0x30, 0xDC, 0x5F, + 0x5E, 0xC5, 0x0B, 0x1A, 0xA6, 0xE1, 0x39, 0xCA, 0xD5, 0x47, 0x5D, + 0x3D, 0xD9, 0x01, 0x5A, 0xD6, 0x51, 0x56, 0x6C, 0x4D, 0x8B, 0x0D, + 0x9A, 0x66, 0xFB, 0xCC, 0xB0, 0x2D, 0x74, 0x12, 0x2B, 0x20, 0xF0, + 0xB1, 0x84, 0x99, 0xDF, 0x4C, 0xCB, 0xC2, 0x34, 0x7E, 0x76, 0x05, + 0x6D, 0xB7, 0xA9, 0x31, 0xD1, 0x17, 0x04, 0xD7, 0x14, 0x58, 0x3A, + 0x61, 0xDE, 0x1B, 0x11, 0x1C, 0x32, 0x0F, 0x9C, 0x16, 0x53, 0x18, + 0xF2, 0x22, 0xFE, 0x44, 0xCF, 0xB2, 0xC3, 0xB5, 0x7A, 0x91, 0x24, + 0x08, 0xE8, 0xA8, 0x60, 0xFC, 0x69, 0x50, 0xAA, 0xD0, 0xA0, 0x7D, + 0xA1, 0x89, 0x62, 0x97, 0x54, 0x5B, 0x1E, 0x95, 0xE0, 0xFF, 0x64, + 0xD2, 0x10, 0xC4, 0x00, 0x48, 0xA3, 0xF7, 0x75, 0xDB, 0x8A, 0x03, + 0xE6, 0xDA, 0x09, 0x3F, 0xDD, 0x94, 0x87, 0x5C, 0x83, 0x02, 0xCD, + 0x4A, 0x90, 0x33, 0x73, 0x67, 0xF6, 0xF3, 0x9D, 0x7F, 0xBF, 0xE2, + 0x52, 0x9B, 0xD8, 0x26, 0xC8, 0x37, 0xC6, 0x3B, 0x81, 0x96, 0x6F, + 0x4B, 0x13, 0xBE, 0x63, 0x2E, 0xE9, 0x79, 0xA7, 0x8C, 0x9F, 0x6E, + 0xBC, 0x8E, 0x29, 0xF5, 0xF9, 0xB6, 0x2F, 0xFD, 0xB4, 0x59, 0x78, + 0x98, 0x06, 0x6A, 0xE7, 0x46, 0x71, 0xBA, 0xD4, 0x25, 0xAB, 0x42, + 0x88, 0xA2, 0x8D, 0xFA, 0x72, 0x07, 0xB9, 0x55, 0xF8, 0xEE, 0xAC, + 0x0A, 0x36, 0x49, 0x2A, 0x68, 0x3C, 0x38, 0xF1, 0xA4, 0x40, 0x28, + 0xD3, 0x7B, 0xBB, 0xC9, 0x43, 0xC1, 0x15, 0xE3, 0xAD, 0xF4, 0x77, + 0xC7, 0x80, 0x9E }; + + const u64bit x = v ^ K; + + const byte t1 = SBOX[get_byte(0, x)]; + const byte t2 = rotate_left(SBOX[get_byte(1, x)], 1); + const byte t3 = rotate_left(SBOX[get_byte(2, x)], 7); + const byte t4 = SBOX[rotate_left(get_byte(3, x), 1)]; + const byte t5 = rotate_left(SBOX[get_byte(4, x)], 1); + const byte t6 = rotate_left(SBOX[get_byte(5, x)], 7); + const byte t7 = SBOX[rotate_left(get_byte(6, x), 1)]; + const byte t8 = SBOX[get_byte(7, x)]; + + const byte y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; + const byte y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; + const byte y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; + const byte y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; + const byte y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; + const byte y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; + const byte y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; + const byte y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; + + return make_u64bit(y1, y2, y3, y4, y5, y6, y7, y8); + } + +inline u64bit F(u64bit v, u64bit K) + { + const u64bit x = v ^ K; + + return Camellia_SBOX1[get_byte(0, x)] ^ + Camellia_SBOX2[get_byte(1, x)] ^ + Camellia_SBOX3[get_byte(2, x)] ^ + Camellia_SBOX4[get_byte(3, x)] ^ + Camellia_SBOX5[get_byte(4, x)] ^ + Camellia_SBOX6[get_byte(5, x)] ^ + Camellia_SBOX7[get_byte(6, x)] ^ + Camellia_SBOX8[get_byte(7, x)]; + } + +inline u64bit FL(u64bit v, u64bit K) + { + u32bit x1 = (v >> 32); + u32bit x2 = (v & 0xFFFFFFFF); + + const u32bit k1 = (K >> 32); + const u32bit k2 = (K & 0xFFFFFFFF); + + x2 ^= rotate_left(x1 & k1, 1); + x1 ^= (x2 | k2); + + return ((static_cast(x1) << 32) | x2); + } + +inline u64bit FLINV(u64bit v, u64bit K) + { + u32bit x1 = (v >> 32); + u32bit x2 = (v & 0xFFFFFFFF); + + const u32bit k1 = (K >> 32); + const u32bit k2 = (K & 0xFFFFFFFF); + + x1 ^= (x2 | k2); + x2 ^= rotate_left(x1 & k1, 1); + + return ((static_cast(x1) << 32) | x2); + } + +/* +* Camellia Encryption +*/ +void encrypt(const byte in[], byte out[], size_t blocks, + const SecureVector& SK, const size_t rounds) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be(in, 0); + u64bit D2 = load_be(in, 1); + + const u64bit* K = &SK[0]; + + D1 ^= *K++; + D2 ^= *K++; + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K++); + D2 = FLINV(D2, *K++); + } + + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + } + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + D2 ^= *K++; + D1 ^= *K++; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +/* +* Camellia Decryption +*/ +void decrypt(const byte in[], byte out[], size_t blocks, + const SecureVector& SK, const size_t rounds) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be(in, 0); + u64bit D2 = load_be(in, 1); + + const u64bit* K = &SK[SK.size()-1]; + + D2 ^= *K--; + D1 ^= *K--; + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K--); + D2 = FLINV(D2, *K--); + } + + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + } + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + D1 ^= *K--; + D2 ^= *K; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +u64bit left_rot_hi(u64bit h, u64bit l, size_t shift) + { + return (h << shift) | ((l >> (64-shift))); + } + +u64bit left_rot_lo(u64bit h, u64bit l, size_t shift) + { + return (h >> (64-shift)) | (l << shift); + } + +/* +* Camellia Key Schedule +*/ +void key_schedule(SecureVector& SK, const byte key[], size_t length) + { + const u64bit Sigma1 = 0xA09E667F3BCC908BULL; + const u64bit Sigma2 = 0xB67AE8584CAA73B2ULL; + const u64bit Sigma3 = 0xC6EF372FE94F82BEULL; + const u64bit Sigma4 = 0x54FF53A5F1D36F1CULL; + const u64bit Sigma5 = 0x10E527FADE682D1DULL; + const u64bit Sigma6 = 0xB05688C2B3E6C1FDULL; + + const u64bit KL_H = load_be(key, 0); + const u64bit KL_L = load_be(key, 1); + + const u64bit KR_H = (length >= 24) ? load_be(key, 2) : 0; + const u64bit KR_L = + (length == 32) ? load_be(key, 3) : ((length == 24) ? ~KR_H : 0); + + u64bit D1 = KL_H ^ KR_H; + u64bit D2 = KL_L ^ KR_L; + D2 ^= F(D1, Sigma1); + D1 ^= F(D2, Sigma2); + D1 ^= KL_H; + D2 ^= KL_L; + D2 ^= F(D1, Sigma3); + D1 ^= F(D2, Sigma4); + + const u64bit KA_H = D1; + const u64bit KA_L = D2; + + D1 = KA_H ^ KR_H; + D2 = KA_L ^ KR_L; + D2 ^= F(D1, Sigma5); + D1 ^= F(D2, Sigma6); + + const u64bit KB_H = D1; + const u64bit KB_L = D2; + + if(length == 16) + { + SK.resize(26); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KA_H; + SK[ 3] = KA_L; + SK[ 4] = left_rot_hi(KL_H, KL_L, 15); + SK[ 5] = left_rot_lo(KL_H, KL_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + SK[ 8] = left_rot_hi(KA_H, KA_L, 30); + SK[ 9] = left_rot_lo(KA_H, KA_L, 30); + SK[10] = left_rot_hi(KL_H, KL_L, 45); + SK[11] = left_rot_lo(KL_H, KL_L, 45); + SK[12] = left_rot_hi(KA_H, KA_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 60); + SK[14] = left_rot_hi(KA_H, KA_L, 60); + SK[15] = left_rot_lo(KA_H, KA_L, 60); + SK[16] = left_rot_lo(KL_H, KL_L, 77-64); + SK[17] = left_rot_hi(KL_H, KL_L, 77-64); + SK[18] = left_rot_lo(KL_H, KL_L, 94-64); + SK[19] = left_rot_hi(KL_H, KL_L, 94-64); + SK[20] = left_rot_lo(KA_H, KA_L, 94-64); + SK[21] = left_rot_hi(KA_H, KA_L, 94-64); + SK[22] = left_rot_lo(KL_H, KL_L, 111-64); + SK[23] = left_rot_hi(KL_H, KL_L, 111-64); + SK[24] = left_rot_lo(KA_H, KA_L, 111-64); + SK[25] = left_rot_hi(KA_H, KA_L, 111-64); + } + else + { + SK.resize(34); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KB_H; + SK[ 3] = KB_L; + + SK[ 4] = left_rot_hi(KR_H, KR_L, 15); + SK[ 5] = left_rot_lo(KR_H, KR_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + + SK[ 8] = left_rot_hi(KR_H, KR_L, 30); + SK[ 9] = left_rot_lo(KR_H, KR_L, 30); + SK[10] = left_rot_hi(KB_H, KB_L, 30); + SK[11] = left_rot_lo(KB_H, KB_L, 30); + + SK[12] = left_rot_hi(KL_H, KL_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 45); + SK[14] = left_rot_hi(KA_H, KA_L, 45); + SK[15] = left_rot_lo(KA_H, KA_L, 45); + + SK[16] = left_rot_hi(KL_H, KL_L, 60); + SK[17] = left_rot_lo(KL_H, KL_L, 60); + SK[18] = left_rot_hi(KR_H, KR_L, 60); + SK[19] = left_rot_lo(KR_H, KR_L, 60); + SK[20] = left_rot_hi(KB_H, KB_L, 60); + SK[21] = left_rot_lo(KB_H, KB_L, 60); + + SK[22] = left_rot_lo(KL_H, KL_L, 77-64); + SK[23] = left_rot_hi(KL_H, KL_L, 77-64); + SK[24] = left_rot_lo(KA_H, KA_L, 77-64); + SK[25] = left_rot_hi(KA_H, KA_L, 77-64); + + SK[26] = left_rot_lo(KR_H, KR_L, 94-64); + SK[27] = left_rot_hi(KR_H, KR_L, 94-64); + SK[28] = left_rot_lo(KA_H, KA_L, 94-64); + SK[29] = left_rot_hi(KA_H, KA_L, 94-64); + SK[30] = left_rot_lo(KL_H, KL_L, 111-64); + SK[31] = left_rot_hi(KL_H, KL_L, 111-64); + SK[32] = left_rot_lo(KB_H, KB_L, 111-64); + SK[33] = left_rot_hi(KB_H, KB_L, 111-64); + } + } + +} + +} + +void Camellia_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 9); + } + +void Camellia_192::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 12); + } + +void Camellia_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK, 12); + } + +void Camellia_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 9); + } + +void Camellia_192::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 12); + } + +void Camellia_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK, 12); + } + +void Camellia_128::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_192::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_256::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +} +/* +* Block Cipher Cascade +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +void Cascade_Cipher::encrypt_n(const byte in[], byte out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / cipher2->block_size()); + + cipher1->encrypt_n(in, out, c1_blocks); + cipher2->encrypt_n(out, out, c2_blocks); + } + +void Cascade_Cipher::decrypt_n(const byte in[], byte out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / cipher2->block_size()); + + cipher2->decrypt_n(in, out, c2_blocks); + cipher1->decrypt_n(out, out, c1_blocks); + } + +void Cascade_Cipher::key_schedule(const byte key[], size_t) + { + const byte* key2 = key + cipher1->maximum_keylength(); + + cipher1->set_key(key , cipher1->maximum_keylength()); + cipher2->set_key(key2, cipher2->maximum_keylength()); + } + +void Cascade_Cipher::clear() + { + cipher1->clear(); + cipher2->clear(); + } + +std::string Cascade_Cipher::name() const + { + return "Cascade(" + cipher1->name() + "," + cipher2->name() + ")"; + } + +BlockCipher* Cascade_Cipher::clone() const + { + return new Cascade_Cipher(cipher1->clone(), + cipher2->clone()); + } + +namespace { + +size_t euclids_algorithm(size_t a, size_t b) + { + while(b != 0) // gcd + { + size_t t = b; + b = a % b; + a = t; + } + + return a; + } + +size_t block_size_for_cascade(size_t bs, size_t bs2) + { + if(bs == bs2) + return bs; + + size_t gcd = euclids_algorithm(bs, bs2); + + return (bs * bs2) / gcd; + } + +} + +Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) : + cipher1(c1), cipher2(c2) + { + block = block_size_for_cascade(c1->block_size(), c2->block_size()); + + if(block_size() % c1->block_size() || block_size() % c2->block_size()) + throw Internal_Error("Failure in " + name() + " constructor"); + } + +Cascade_Cipher::~Cascade_Cipher() + { + delete cipher1; + delete cipher2; + } + +} +/* +* CAST-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* CAST-128 Round Type 1 +*/ +inline void R1(u32bit& L, u32bit R, u32bit MK, u32bit RK) + { + u32bit T = rotate_left(MK + R, RK); + L ^= (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - + CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 2 +*/ +inline void R2(u32bit& L, u32bit R, u32bit MK, u32bit RK) + { + u32bit T = rotate_left(MK ^ R, RK); + L ^= (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 3 +*/ +inline void R3(u32bit& L, u32bit R, u32bit MK, u32bit RK) + { + u32bit T = rotate_left(MK - R, RK); + L ^= ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ + CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; + } + +} + +/* +* CAST-128 Encryption +*/ +void CAST_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + R1(L, R, MK[ 0], RK[ 0]); + R2(R, L, MK[ 1], RK[ 1]); + R3(L, R, MK[ 2], RK[ 2]); + R1(R, L, MK[ 3], RK[ 3]); + R2(L, R, MK[ 4], RK[ 4]); + R3(R, L, MK[ 5], RK[ 5]); + R1(L, R, MK[ 6], RK[ 6]); + R2(R, L, MK[ 7], RK[ 7]); + R3(L, R, MK[ 8], RK[ 8]); + R1(R, L, MK[ 9], RK[ 9]); + R2(L, R, MK[10], RK[10]); + R3(R, L, MK[11], RK[11]); + R1(L, R, MK[12], RK[12]); + R2(R, L, MK[13], RK[13]); + R3(L, R, MK[14], RK[14]); + R1(R, L, MK[15], RK[15]); + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-128 Decryption +*/ +void CAST_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + R1(L, R, MK[15], RK[15]); + R3(R, L, MK[14], RK[14]); + R2(L, R, MK[13], RK[13]); + R1(R, L, MK[12], RK[12]); + R3(L, R, MK[11], RK[11]); + R2(R, L, MK[10], RK[10]); + R1(L, R, MK[ 9], RK[ 9]); + R3(R, L, MK[ 8], RK[ 8]); + R2(L, R, MK[ 7], RK[ 7]); + R1(R, L, MK[ 6], RK[ 6]); + R3(L, R, MK[ 5], RK[ 5]); + R2(R, L, MK[ 4], RK[ 4]); + R1(L, R, MK[ 3], RK[ 3]); + R3(R, L, MK[ 2], RK[ 2]); + R2(L, R, MK[ 1], RK[ 1]); + R1(R, L, MK[ 0], RK[ 0]); + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-128 Key Schedule +*/ +void CAST_128::key_schedule(const byte key[], size_t length) + { + clear(); + SecureVector X(4); + for(size_t j = 0; j != length; ++j) + X[j/4] = (X[j/4] << 8) + key[j]; + + cast_ks(MK, X); + cast_ks(RK, X); + + for(size_t j = 0; j != 16; ++j) + RK[j] %= 32; + } + +/* +* S-Box Based Key Expansion +*/ +void CAST_128::cast_ks(MemoryRegion& K, + MemoryRegion& X) + { + class ByteReader + { + public: + byte operator()(size_t i) { return (X[i/4] >> (8*(3 - (i%4)))); } + ByteReader(const u32bit* x) : X(x) {} + private: + const u32bit* X; + }; + + SecureVector Z(4); + ByteReader x(&X[0]), z(&Z[0]); + + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)]; + K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)]; + K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)]; + K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)]; + K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)]; + K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)]; + K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)]; + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)]; + K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)]; + K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)]; + K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)]; + K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)]; + K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)]; + K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)]; + } + +} +/* +* CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* CAST-256 Round Type 1 +*/ +void round1(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask + in, rot); + out ^= (CAST_SBOX1[get_byte(0, temp)] ^ CAST_SBOX2[get_byte(1, temp)]) - + CAST_SBOX3[get_byte(2, temp)] + CAST_SBOX4[get_byte(3, temp)]; + } + +/* +* CAST-256 Round Type 2 +*/ +void round2(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask ^ in, rot); + out ^= (CAST_SBOX1[get_byte(0, temp)] - CAST_SBOX2[get_byte(1, temp)] + + CAST_SBOX3[get_byte(2, temp)]) ^ CAST_SBOX4[get_byte(3, temp)]; + } + +/* +* CAST-256 Round Type 3 +*/ +void round3(u32bit& out, u32bit in, u32bit mask, u32bit rot) + { + u32bit temp = rotate_left(mask - in, rot); + out ^= ((CAST_SBOX1[get_byte(0, temp)] + CAST_SBOX2[get_byte(1, temp)]) ^ + CAST_SBOX3[get_byte(2, temp)]) - CAST_SBOX4[get_byte(3, temp)]; + } + +} + +/* +* CAST-256 Encryption +*/ +void CAST_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_be(in, 0); + u32bit B = load_be(in, 1); + u32bit C = load_be(in, 2); + u32bit D = load_be(in, 3); + + round1(C, D, MK[ 0], RK[ 0]); round2(B, C, MK[ 1], RK[ 1]); + round3(A, B, MK[ 2], RK[ 2]); round1(D, A, MK[ 3], RK[ 3]); + round1(C, D, MK[ 4], RK[ 4]); round2(B, C, MK[ 5], RK[ 5]); + round3(A, B, MK[ 6], RK[ 6]); round1(D, A, MK[ 7], RK[ 7]); + round1(C, D, MK[ 8], RK[ 8]); round2(B, C, MK[ 9], RK[ 9]); + round3(A, B, MK[10], RK[10]); round1(D, A, MK[11], RK[11]); + round1(C, D, MK[12], RK[12]); round2(B, C, MK[13], RK[13]); + round3(A, B, MK[14], RK[14]); round1(D, A, MK[15], RK[15]); + round1(C, D, MK[16], RK[16]); round2(B, C, MK[17], RK[17]); + round3(A, B, MK[18], RK[18]); round1(D, A, MK[19], RK[19]); + round1(C, D, MK[20], RK[20]); round2(B, C, MK[21], RK[21]); + round3(A, B, MK[22], RK[22]); round1(D, A, MK[23], RK[23]); + round1(D, A, MK[27], RK[27]); round3(A, B, MK[26], RK[26]); + round2(B, C, MK[25], RK[25]); round1(C, D, MK[24], RK[24]); + round1(D, A, MK[31], RK[31]); round3(A, B, MK[30], RK[30]); + round2(B, C, MK[29], RK[29]); round1(C, D, MK[28], RK[28]); + round1(D, A, MK[35], RK[35]); round3(A, B, MK[34], RK[34]); + round2(B, C, MK[33], RK[33]); round1(C, D, MK[32], RK[32]); + round1(D, A, MK[39], RK[39]); round3(A, B, MK[38], RK[38]); + round2(B, C, MK[37], RK[37]); round1(C, D, MK[36], RK[36]); + round1(D, A, MK[43], RK[43]); round3(A, B, MK[42], RK[42]); + round2(B, C, MK[41], RK[41]); round1(C, D, MK[40], RK[40]); + round1(D, A, MK[47], RK[47]); round3(A, B, MK[46], RK[46]); + round2(B, C, MK[45], RK[45]); round1(C, D, MK[44], RK[44]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Decryption +*/ +void CAST_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_be(in, 0); + u32bit B = load_be(in, 1); + u32bit C = load_be(in, 2); + u32bit D = load_be(in, 3); + + round1(C, D, MK[44], RK[44]); round2(B, C, MK[45], RK[45]); + round3(A, B, MK[46], RK[46]); round1(D, A, MK[47], RK[47]); + round1(C, D, MK[40], RK[40]); round2(B, C, MK[41], RK[41]); + round3(A, B, MK[42], RK[42]); round1(D, A, MK[43], RK[43]); + round1(C, D, MK[36], RK[36]); round2(B, C, MK[37], RK[37]); + round3(A, B, MK[38], RK[38]); round1(D, A, MK[39], RK[39]); + round1(C, D, MK[32], RK[32]); round2(B, C, MK[33], RK[33]); + round3(A, B, MK[34], RK[34]); round1(D, A, MK[35], RK[35]); + round1(C, D, MK[28], RK[28]); round2(B, C, MK[29], RK[29]); + round3(A, B, MK[30], RK[30]); round1(D, A, MK[31], RK[31]); + round1(C, D, MK[24], RK[24]); round2(B, C, MK[25], RK[25]); + round3(A, B, MK[26], RK[26]); round1(D, A, MK[27], RK[27]); + round1(D, A, MK[23], RK[23]); round3(A, B, MK[22], RK[22]); + round2(B, C, MK[21], RK[21]); round1(C, D, MK[20], RK[20]); + round1(D, A, MK[19], RK[19]); round3(A, B, MK[18], RK[18]); + round2(B, C, MK[17], RK[17]); round1(C, D, MK[16], RK[16]); + round1(D, A, MK[15], RK[15]); round3(A, B, MK[14], RK[14]); + round2(B, C, MK[13], RK[13]); round1(C, D, MK[12], RK[12]); + round1(D, A, MK[11], RK[11]); round3(A, B, MK[10], RK[10]); + round2(B, C, MK[ 9], RK[ 9]); round1(C, D, MK[ 8], RK[ 8]); + round1(D, A, MK[ 7], RK[ 7]); round3(A, B, MK[ 6], RK[ 6]); + round2(B, C, MK[ 5], RK[ 5]); round1(C, D, MK[ 4], RK[ 4]); + round1(D, A, MK[ 3], RK[ 3]); round3(A, B, MK[ 2], RK[ 2]); + round2(B, C, MK[ 1], RK[ 1]); round1(C, D, MK[ 0], RK[ 0]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Key Schedule +*/ +void CAST_256::key_schedule(const byte key[], size_t length) + { + SecureVector K(8); + for(size_t j = 0; j != length; ++j) + K[j/4] = (K[j/4] << 8) + key[j]; + + u32bit A = K[0], B = K[1], C = K[2], D = K[3], + E = K[4], F = K[5], G = K[6], H = K[7]; + + for(size_t j = 0; j != 48; j += 4) + { + round1(G, H, KEY_MASK[4*j+ 0], KEY_ROT[(4*j+ 0) % 32]); + round2(F, G, KEY_MASK[4*j+ 1], KEY_ROT[(4*j+ 1) % 32]); + round3(E, F, KEY_MASK[4*j+ 2], KEY_ROT[(4*j+ 2) % 32]); + round1(D, E, KEY_MASK[4*j+ 3], KEY_ROT[(4*j+ 3) % 32]); + round2(C, D, KEY_MASK[4*j+ 4], KEY_ROT[(4*j+ 4) % 32]); + round3(B, C, KEY_MASK[4*j+ 5], KEY_ROT[(4*j+ 5) % 32]); + round1(A, B, KEY_MASK[4*j+ 6], KEY_ROT[(4*j+ 6) % 32]); + round2(H, A, KEY_MASK[4*j+ 7], KEY_ROT[(4*j+ 7) % 32]); + round1(G, H, KEY_MASK[4*j+ 8], KEY_ROT[(4*j+ 8) % 32]); + round2(F, G, KEY_MASK[4*j+ 9], KEY_ROT[(4*j+ 9) % 32]); + round3(E, F, KEY_MASK[4*j+10], KEY_ROT[(4*j+10) % 32]); + round1(D, E, KEY_MASK[4*j+11], KEY_ROT[(4*j+11) % 32]); + round2(C, D, KEY_MASK[4*j+12], KEY_ROT[(4*j+12) % 32]); + round3(B, C, KEY_MASK[4*j+13], KEY_ROT[(4*j+13) % 32]); + round1(A, B, KEY_MASK[4*j+14], KEY_ROT[(4*j+14) % 32]); + round2(H, A, KEY_MASK[4*j+15], KEY_ROT[(4*j+15) % 32]); + + RK[j ] = (A % 32); + RK[j+1] = (C % 32); + RK[j+2] = (E % 32); + RK[j+3] = (G % 32); + MK[j ] = H; + MK[j+1] = F; + MK[j+2] = D; + MK[j+3] = B; + } + } + +} +/* +* S-Box Tables for CAST-128 and CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u32bit CAST_SBOX1[256] = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; + +const u32bit CAST_SBOX2[256] = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; + +const u32bit CAST_SBOX3[256] = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; + +const u32bit CAST_SBOX4[256] = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; + +const u32bit CAST_128::S5[256] = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; + +const u32bit CAST_128::S6[256] = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; + +const u32bit CAST_128::S7[256] = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; + +const u32bit CAST_128::S8[256] = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; + +const u32bit CAST_256::KEY_MASK[192] = { + 0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE, + 0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984, + 0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A, + 0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510, + 0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6, + 0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C, + 0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662, + 0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28, + 0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE, + 0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4, + 0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A, + 0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340, + 0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906, + 0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC, + 0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492, + 0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58, + 0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E, + 0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4, + 0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA, + 0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170, + 0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736, + 0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC, + 0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2, + 0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888, + 0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E, + 0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414, + 0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA, + 0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0, + 0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566, + 0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C, + 0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2, + 0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 }; + +const byte CAST_256::KEY_ROT[32] = { + 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C, 0x1D, 0x0E, + 0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16, 0x07, 0x18, 0x09, 0x1A, + 0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00, 0x11, 0x02 }; + +} +/* +* DES +* (C) 1999-2008 Jack Lloyd +* +* Based on a public domain implemenation by Phil Karn (who in turn +* credited Richard Outerbridge and Jim Gillogly) +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* DES Key Schedule +*/ +void des_key_schedule(u32bit round_key[32], const byte key[8]) + { + static const byte ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 }; + + u32bit C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) | + ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) | + ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) | + ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) | + ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) | + ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) | + ((key[3] & 0x40) << 9) | ((key[2] & 0x40) << 8) | + ((key[1] & 0x40) << 7) | ((key[0] & 0x40) << 6) | + ((key[7] & 0x20) << 6) | ((key[6] & 0x20) << 5) | + ((key[5] & 0x20) << 4) | ((key[4] & 0x20) << 3) | + ((key[3] & 0x20) << 2) | ((key[2] & 0x20) << 1) | + ((key[1] & 0x20) ) | ((key[0] & 0x20) >> 1) | + ((key[7] & 0x10) >> 1) | ((key[6] & 0x10) >> 2) | + ((key[5] & 0x10) >> 3) | ((key[4] & 0x10) >> 4); + u32bit D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) | + ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) | + ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) | + ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) | + ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) | + ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) | + ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) | + ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) | + ((key[7] & 0x08) << 8) | ((key[6] & 0x08) << 7) | + ((key[5] & 0x08) << 6) | ((key[4] & 0x08) << 5) | + ((key[3] & 0x08) << 4) | ((key[2] & 0x08) << 3) | + ((key[1] & 0x08) << 2) | ((key[0] & 0x08) << 1) | + ((key[3] & 0x10) >> 1) | ((key[2] & 0x10) >> 2) | + ((key[1] & 0x10) >> 3) | ((key[0] & 0x10) >> 4); + + for(size_t i = 0; i != 16; ++i) + { + C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF; + D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF; + round_key[2*i ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) | + ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) | + ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) | + ((C & 0x01000000) >> 6) | ((C & 0x00100000) >> 4) | + ((C & 0x00010000) << 3) | ((C & 0x08000000) >> 2) | + ((C & 0x00800000) << 1) | ((D & 0x00000010) << 8) | + ((D & 0x00000002) << 7) | ((D & 0x00000001) << 2) | + ((D & 0x00000200) ) | ((D & 0x00008000) >> 2) | + ((D & 0x00000088) >> 3) | ((D & 0x00001000) >> 7) | + ((D & 0x00080000) >> 9) | ((D & 0x02020000) >> 14) | + ((D & 0x00400000) >> 21); + round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) | + ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) | + ((C & 0x00001000) << 9) | ((C & 0x00040000) << 6) | + ((C & 0x02400000) << 4) | ((C & 0x00008000) << 2) | + ((C & 0x00200000) >> 1) | ((C & 0x04000000) >> 10) | + ((D & 0x00000020) << 6) | ((D & 0x00000100) ) | + ((D & 0x00000800) >> 1) | ((D & 0x00000040) >> 3) | + ((D & 0x00010000) >> 4) | ((D & 0x00000400) >> 5) | + ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) | + ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) | + ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26); + } + } + +/* +* DES Encryption +*/ +void des_encrypt(u32bit& L, u32bit& R, + const u32bit round_key[32]) + { + for(size_t i = 0; i != 16; i += 2) + { + u32bit T0, T1; + + T0 = rotate_right(R, 4) ^ round_key[2*i]; + T1 = R ^ round_key[2*i + 1]; + + L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + + T0 = rotate_right(L, 4) ^ round_key[2*i + 2]; + T1 = L ^ round_key[2*i + 3]; + + R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + } + +/* +* DES Decryption +*/ +void des_decrypt(u32bit& L, u32bit& R, + const u32bit round_key[32]) + { + for(size_t i = 16; i != 0; i -= 2) + { + u32bit T0, T1; + + T0 = rotate_right(R, 4) ^ round_key[2*i - 2]; + T1 = R ^ round_key[2*i - 1]; + + L ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + + T0 = rotate_right(L, 4) ^ round_key[2*i - 4]; + T1 = L ^ round_key[2*i - 3]; + + R ^= DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + } + +} + +/* +* DES Encryption +*/ +void DES::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_encrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DES Decryption +*/ +void DES::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_decrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DES Key Schedule +*/ +void DES::key_schedule(const byte key[], size_t) + { + des_key_schedule(&round_key[0], key); + } + +/* +* TripleDES Encryption +*/ +void TripleDES::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_encrypt(L, R, &round_key[0]); + des_decrypt(R, L, &round_key[32]); + des_encrypt(L, R, &round_key[64]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TripleDES Decryption +*/ +void TripleDES::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | + (DES_IPTAB1[in[2]] << 2) | (DES_IPTAB1[in[3]] << 3) | + (DES_IPTAB1[in[4]] << 4) | (DES_IPTAB1[in[5]] << 5) | + (DES_IPTAB1[in[6]] << 6) | (DES_IPTAB2[in[7]] ); + + u32bit L = static_cast(T >> 32); + u32bit R = static_cast(T); + + des_decrypt(L, R, &round_key[64]); + des_encrypt(R, L, &round_key[32]); + des_decrypt(L, R, &round_key[0]); + + T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + + T = rotate_left(T, 32); + + store_be(T, out); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TripleDES Key Schedule +*/ +void TripleDES::key_schedule(const byte key[], size_t length) + { + des_key_schedule(&round_key[0], key); + des_key_schedule(&round_key[32], key + 8); + + if(length == 24) + des_key_schedule(&round_key[64], key + 16); + else + copy_mem(&round_key[64], &round_key[0], 32); + } + +} +/* +* Substitution/Permutation Tables for DES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u32bit DES_SPBOX1[256] = { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, + 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, + 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, + 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, + 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, + 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, + 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, + 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, + 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, + 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, + 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, + 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + +const u32bit DES_SPBOX2[256] = { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, + 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, + 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, + 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, + 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, + 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, + 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, + 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, + 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, + 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, + 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, + 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + +const u32bit DES_SPBOX3[256] = { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, + 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, + 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, + 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, + 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, + 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, + 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, + 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, + 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, + 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, + 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, + 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + +const u32bit DES_SPBOX4[256] = { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, + 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, + 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + +const u32bit DES_SPBOX5[256] = { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, + 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, + 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, + 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, + 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, + 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, + 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, + 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, + 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, + 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, + 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, + 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + +const u32bit DES_SPBOX6[256] = { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, + 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, + 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, + 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, + 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, + 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, + 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, + 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, + 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, + 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, + 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, + 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + +const u32bit DES_SPBOX7[256] = { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, + 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, + 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, + 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, + 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, + 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, + 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, + 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, + 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, + 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, + 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, + 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + +const u32bit DES_SPBOX8[256] = { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, + 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, + 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, + 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, + 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, + 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, + 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, + 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, + 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, + 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, + 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, + 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + +const u64bit DES_IPTAB1[256] = { +0x0000000000000000ULL, 0x0000000200000000ULL, 0x0000000000000002ULL, 0x0000000200000002ULL, +0x0000020000000000ULL, 0x0000020200000000ULL, 0x0000020000000002ULL, 0x0000020200000002ULL, +0x0000000000000200ULL, 0x0000000200000200ULL, 0x0000000000000202ULL, 0x0000000200000202ULL, +0x0000020000000200ULL, 0x0000020200000200ULL, 0x0000020000000202ULL, 0x0000020200000202ULL, +0x0002000000000000ULL, 0x0002000200000000ULL, 0x0002000000000002ULL, 0x0002000200000002ULL, +0x0002020000000000ULL, 0x0002020200000000ULL, 0x0002020000000002ULL, 0x0002020200000002ULL, +0x0002000000000200ULL, 0x0002000200000200ULL, 0x0002000000000202ULL, 0x0002000200000202ULL, +0x0002020000000200ULL, 0x0002020200000200ULL, 0x0002020000000202ULL, 0x0002020200000202ULL, +0x0000000000020000ULL, 0x0000000200020000ULL, 0x0000000000020002ULL, 0x0000000200020002ULL, +0x0000020000020000ULL, 0x0000020200020000ULL, 0x0000020000020002ULL, 0x0000020200020002ULL, +0x0000000000020200ULL, 0x0000000200020200ULL, 0x0000000000020202ULL, 0x0000000200020202ULL, +0x0000020000020200ULL, 0x0000020200020200ULL, 0x0000020000020202ULL, 0x0000020200020202ULL, +0x0002000000020000ULL, 0x0002000200020000ULL, 0x0002000000020002ULL, 0x0002000200020002ULL, +0x0002020000020000ULL, 0x0002020200020000ULL, 0x0002020000020002ULL, 0x0002020200020002ULL, +0x0002000000020200ULL, 0x0002000200020200ULL, 0x0002000000020202ULL, 0x0002000200020202ULL, +0x0002020000020200ULL, 0x0002020200020200ULL, 0x0002020000020202ULL, 0x0002020200020202ULL, +0x0200000000000000ULL, 0x0200000200000000ULL, 0x0200000000000002ULL, 0x0200000200000002ULL, +0x0200020000000000ULL, 0x0200020200000000ULL, 0x0200020000000002ULL, 0x0200020200000002ULL, +0x0200000000000200ULL, 0x0200000200000200ULL, 0x0200000000000202ULL, 0x0200000200000202ULL, +0x0200020000000200ULL, 0x0200020200000200ULL, 0x0200020000000202ULL, 0x0200020200000202ULL, +0x0202000000000000ULL, 0x0202000200000000ULL, 0x0202000000000002ULL, 0x0202000200000002ULL, +0x0202020000000000ULL, 0x0202020200000000ULL, 0x0202020000000002ULL, 0x0202020200000002ULL, +0x0202000000000200ULL, 0x0202000200000200ULL, 0x0202000000000202ULL, 0x0202000200000202ULL, +0x0202020000000200ULL, 0x0202020200000200ULL, 0x0202020000000202ULL, 0x0202020200000202ULL, +0x0200000000020000ULL, 0x0200000200020000ULL, 0x0200000000020002ULL, 0x0200000200020002ULL, +0x0200020000020000ULL, 0x0200020200020000ULL, 0x0200020000020002ULL, 0x0200020200020002ULL, +0x0200000000020200ULL, 0x0200000200020200ULL, 0x0200000000020202ULL, 0x0200000200020202ULL, +0x0200020000020200ULL, 0x0200020200020200ULL, 0x0200020000020202ULL, 0x0200020200020202ULL, +0x0202000000020000ULL, 0x0202000200020000ULL, 0x0202000000020002ULL, 0x0202000200020002ULL, +0x0202020000020000ULL, 0x0202020200020000ULL, 0x0202020000020002ULL, 0x0202020200020002ULL, +0x0202000000020200ULL, 0x0202000200020200ULL, 0x0202000000020202ULL, 0x0202000200020202ULL, +0x0202020000020200ULL, 0x0202020200020200ULL, 0x0202020000020202ULL, 0x0202020200020202ULL, +0x0000000002000000ULL, 0x0000000202000000ULL, 0x0000000002000002ULL, 0x0000000202000002ULL, +0x0000020002000000ULL, 0x0000020202000000ULL, 0x0000020002000002ULL, 0x0000020202000002ULL, +0x0000000002000200ULL, 0x0000000202000200ULL, 0x0000000002000202ULL, 0x0000000202000202ULL, +0x0000020002000200ULL, 0x0000020202000200ULL, 0x0000020002000202ULL, 0x0000020202000202ULL, +0x0002000002000000ULL, 0x0002000202000000ULL, 0x0002000002000002ULL, 0x0002000202000002ULL, +0x0002020002000000ULL, 0x0002020202000000ULL, 0x0002020002000002ULL, 0x0002020202000002ULL, +0x0002000002000200ULL, 0x0002000202000200ULL, 0x0002000002000202ULL, 0x0002000202000202ULL, +0x0002020002000200ULL, 0x0002020202000200ULL, 0x0002020002000202ULL, 0x0002020202000202ULL, +0x0000000002020000ULL, 0x0000000202020000ULL, 0x0000000002020002ULL, 0x0000000202020002ULL, +0x0000020002020000ULL, 0x0000020202020000ULL, 0x0000020002020002ULL, 0x0000020202020002ULL, +0x0000000002020200ULL, 0x0000000202020200ULL, 0x0000000002020202ULL, 0x0000000202020202ULL, +0x0000020002020200ULL, 0x0000020202020200ULL, 0x0000020002020202ULL, 0x0000020202020202ULL, +0x0002000002020000ULL, 0x0002000202020000ULL, 0x0002000002020002ULL, 0x0002000202020002ULL, +0x0002020002020000ULL, 0x0002020202020000ULL, 0x0002020002020002ULL, 0x0002020202020002ULL, +0x0002000002020200ULL, 0x0002000202020200ULL, 0x0002000002020202ULL, 0x0002000202020202ULL, +0x0002020002020200ULL, 0x0002020202020200ULL, 0x0002020002020202ULL, 0x0002020202020202ULL, +0x0200000002000000ULL, 0x0200000202000000ULL, 0x0200000002000002ULL, 0x0200000202000002ULL, +0x0200020002000000ULL, 0x0200020202000000ULL, 0x0200020002000002ULL, 0x0200020202000002ULL, +0x0200000002000200ULL, 0x0200000202000200ULL, 0x0200000002000202ULL, 0x0200000202000202ULL, +0x0200020002000200ULL, 0x0200020202000200ULL, 0x0200020002000202ULL, 0x0200020202000202ULL, +0x0202000002000000ULL, 0x0202000202000000ULL, 0x0202000002000002ULL, 0x0202000202000002ULL, +0x0202020002000000ULL, 0x0202020202000000ULL, 0x0202020002000002ULL, 0x0202020202000002ULL, +0x0202000002000200ULL, 0x0202000202000200ULL, 0x0202000002000202ULL, 0x0202000202000202ULL, +0x0202020002000200ULL, 0x0202020202000200ULL, 0x0202020002000202ULL, 0x0202020202000202ULL, +0x0200000002020000ULL, 0x0200000202020000ULL, 0x0200000002020002ULL, 0x0200000202020002ULL, +0x0200020002020000ULL, 0x0200020202020000ULL, 0x0200020002020002ULL, 0x0200020202020002ULL, +0x0200000002020200ULL, 0x0200000202020200ULL, 0x0200000002020202ULL, 0x0200000202020202ULL, +0x0200020002020200ULL, 0x0200020202020200ULL, 0x0200020002020202ULL, 0x0200020202020202ULL, +0x0202000002020000ULL, 0x0202000202020000ULL, 0x0202000002020002ULL, 0x0202000202020002ULL, +0x0202020002020000ULL, 0x0202020202020000ULL, 0x0202020002020002ULL, 0x0202020202020002ULL, +0x0202000002020200ULL, 0x0202000202020200ULL, 0x0202000002020202ULL, 0x0202000202020202ULL, +0x0202020002020200ULL, 0x0202020202020200ULL, 0x0202020002020202ULL, 0x0202020202020202ULL }; + +const u64bit DES_IPTAB2[256] = { +0x0000000000000000ULL, 0x0000010000000000ULL, 0x0000000000000100ULL, 0x0000010000000100ULL, +0x0001000000000000ULL, 0x0001010000000000ULL, 0x0001000000000100ULL, 0x0001010000000100ULL, +0x0000000000010000ULL, 0x0000010000010000ULL, 0x0000000000010100ULL, 0x0000010000010100ULL, +0x0001000000010000ULL, 0x0001010000010000ULL, 0x0001000000010100ULL, 0x0001010000010100ULL, +0x0100000000000000ULL, 0x0100010000000000ULL, 0x0100000000000100ULL, 0x0100010000000100ULL, +0x0101000000000000ULL, 0x0101010000000000ULL, 0x0101000000000100ULL, 0x0101010000000100ULL, +0x0100000000010000ULL, 0x0100010000010000ULL, 0x0100000000010100ULL, 0x0100010000010100ULL, +0x0101000000010000ULL, 0x0101010000010000ULL, 0x0101000000010100ULL, 0x0101010000010100ULL, +0x0000000001000000ULL, 0x0000010001000000ULL, 0x0000000001000100ULL, 0x0000010001000100ULL, +0x0001000001000000ULL, 0x0001010001000000ULL, 0x0001000001000100ULL, 0x0001010001000100ULL, +0x0000000001010000ULL, 0x0000010001010000ULL, 0x0000000001010100ULL, 0x0000010001010100ULL, +0x0001000001010000ULL, 0x0001010001010000ULL, 0x0001000001010100ULL, 0x0001010001010100ULL, +0x0100000001000000ULL, 0x0100010001000000ULL, 0x0100000001000100ULL, 0x0100010001000100ULL, +0x0101000001000000ULL, 0x0101010001000000ULL, 0x0101000001000100ULL, 0x0101010001000100ULL, +0x0100000001010000ULL, 0x0100010001010000ULL, 0x0100000001010100ULL, 0x0100010001010100ULL, +0x0101000001010000ULL, 0x0101010001010000ULL, 0x0101000001010100ULL, 0x0101010001010100ULL, +0x0000000100000000ULL, 0x0000010100000000ULL, 0x0000000100000100ULL, 0x0000010100000100ULL, +0x0001000100000000ULL, 0x0001010100000000ULL, 0x0001000100000100ULL, 0x0001010100000100ULL, +0x0000000100010000ULL, 0x0000010100010000ULL, 0x0000000100010100ULL, 0x0000010100010100ULL, +0x0001000100010000ULL, 0x0001010100010000ULL, 0x0001000100010100ULL, 0x0001010100010100ULL, +0x0100000100000000ULL, 0x0100010100000000ULL, 0x0100000100000100ULL, 0x0100010100000100ULL, +0x0101000100000000ULL, 0x0101010100000000ULL, 0x0101000100000100ULL, 0x0101010100000100ULL, +0x0100000100010000ULL, 0x0100010100010000ULL, 0x0100000100010100ULL, 0x0100010100010100ULL, +0x0101000100010000ULL, 0x0101010100010000ULL, 0x0101000100010100ULL, 0x0101010100010100ULL, +0x0000000101000000ULL, 0x0000010101000000ULL, 0x0000000101000100ULL, 0x0000010101000100ULL, +0x0001000101000000ULL, 0x0001010101000000ULL, 0x0001000101000100ULL, 0x0001010101000100ULL, +0x0000000101010000ULL, 0x0000010101010000ULL, 0x0000000101010100ULL, 0x0000010101010100ULL, +0x0001000101010000ULL, 0x0001010101010000ULL, 0x0001000101010100ULL, 0x0001010101010100ULL, +0x0100000101000000ULL, 0x0100010101000000ULL, 0x0100000101000100ULL, 0x0100010101000100ULL, +0x0101000101000000ULL, 0x0101010101000000ULL, 0x0101000101000100ULL, 0x0101010101000100ULL, +0x0100000101010000ULL, 0x0100010101010000ULL, 0x0100000101010100ULL, 0x0100010101010100ULL, +0x0101000101010000ULL, 0x0101010101010000ULL, 0x0101000101010100ULL, 0x0101010101010100ULL, +0x0000000000000001ULL, 0x0000010000000001ULL, 0x0000000000000101ULL, 0x0000010000000101ULL, +0x0001000000000001ULL, 0x0001010000000001ULL, 0x0001000000000101ULL, 0x0001010000000101ULL, +0x0000000000010001ULL, 0x0000010000010001ULL, 0x0000000000010101ULL, 0x0000010000010101ULL, +0x0001000000010001ULL, 0x0001010000010001ULL, 0x0001000000010101ULL, 0x0001010000010101ULL, +0x0100000000000001ULL, 0x0100010000000001ULL, 0x0100000000000101ULL, 0x0100010000000101ULL, +0x0101000000000001ULL, 0x0101010000000001ULL, 0x0101000000000101ULL, 0x0101010000000101ULL, +0x0100000000010001ULL, 0x0100010000010001ULL, 0x0100000000010101ULL, 0x0100010000010101ULL, +0x0101000000010001ULL, 0x0101010000010001ULL, 0x0101000000010101ULL, 0x0101010000010101ULL, +0x0000000001000001ULL, 0x0000010001000001ULL, 0x0000000001000101ULL, 0x0000010001000101ULL, +0x0001000001000001ULL, 0x0001010001000001ULL, 0x0001000001000101ULL, 0x0001010001000101ULL, +0x0000000001010001ULL, 0x0000010001010001ULL, 0x0000000001010101ULL, 0x0000010001010101ULL, +0x0001000001010001ULL, 0x0001010001010001ULL, 0x0001000001010101ULL, 0x0001010001010101ULL, +0x0100000001000001ULL, 0x0100010001000001ULL, 0x0100000001000101ULL, 0x0100010001000101ULL, +0x0101000001000001ULL, 0x0101010001000001ULL, 0x0101000001000101ULL, 0x0101010001000101ULL, +0x0100000001010001ULL, 0x0100010001010001ULL, 0x0100000001010101ULL, 0x0100010001010101ULL, +0x0101000001010001ULL, 0x0101010001010001ULL, 0x0101000001010101ULL, 0x0101010001010101ULL, +0x0000000100000001ULL, 0x0000010100000001ULL, 0x0000000100000101ULL, 0x0000010100000101ULL, +0x0001000100000001ULL, 0x0001010100000001ULL, 0x0001000100000101ULL, 0x0001010100000101ULL, +0x0000000100010001ULL, 0x0000010100010001ULL, 0x0000000100010101ULL, 0x0000010100010101ULL, +0x0001000100010001ULL, 0x0001010100010001ULL, 0x0001000100010101ULL, 0x0001010100010101ULL, +0x0100000100000001ULL, 0x0100010100000001ULL, 0x0100000100000101ULL, 0x0100010100000101ULL, +0x0101000100000001ULL, 0x0101010100000001ULL, 0x0101000100000101ULL, 0x0101010100000101ULL, +0x0100000100010001ULL, 0x0100010100010001ULL, 0x0100000100010101ULL, 0x0100010100010101ULL, +0x0101000100010001ULL, 0x0101010100010001ULL, 0x0101000100010101ULL, 0x0101010100010101ULL, +0x0000000101000001ULL, 0x0000010101000001ULL, 0x0000000101000101ULL, 0x0000010101000101ULL, +0x0001000101000001ULL, 0x0001010101000001ULL, 0x0001000101000101ULL, 0x0001010101000101ULL, +0x0000000101010001ULL, 0x0000010101010001ULL, 0x0000000101010101ULL, 0x0000010101010101ULL, +0x0001000101010001ULL, 0x0001010101010001ULL, 0x0001000101010101ULL, 0x0001010101010101ULL, +0x0100000101000001ULL, 0x0100010101000001ULL, 0x0100000101000101ULL, 0x0100010101000101ULL, +0x0101000101000001ULL, 0x0101010101000001ULL, 0x0101000101000101ULL, 0x0101010101000101ULL, +0x0100000101010001ULL, 0x0100010101010001ULL, 0x0100000101010101ULL, 0x0100010101010101ULL, +0x0101000101010001ULL, 0x0101010101010001ULL, 0x0101000101010101ULL, 0x0101010101010101ULL }; + +const u64bit DES_FPTAB1[256] = { +0x0000000000000000ULL, 0x0000000100000000ULL, 0x0000000004000000ULL, 0x0000000104000000ULL, +0x0000000000040000ULL, 0x0000000100040000ULL, 0x0000000004040000ULL, 0x0000000104040000ULL, +0x0000000000000400ULL, 0x0000000100000400ULL, 0x0000000004000400ULL, 0x0000000104000400ULL, +0x0000000000040400ULL, 0x0000000100040400ULL, 0x0000000004040400ULL, 0x0000000104040400ULL, +0x0000000000000004ULL, 0x0000000100000004ULL, 0x0000000004000004ULL, 0x0000000104000004ULL, +0x0000000000040004ULL, 0x0000000100040004ULL, 0x0000000004040004ULL, 0x0000000104040004ULL, +0x0000000000000404ULL, 0x0000000100000404ULL, 0x0000000004000404ULL, 0x0000000104000404ULL, +0x0000000000040404ULL, 0x0000000100040404ULL, 0x0000000004040404ULL, 0x0000000104040404ULL, +0x0400000000000000ULL, 0x0400000100000000ULL, 0x0400000004000000ULL, 0x0400000104000000ULL, +0x0400000000040000ULL, 0x0400000100040000ULL, 0x0400000004040000ULL, 0x0400000104040000ULL, +0x0400000000000400ULL, 0x0400000100000400ULL, 0x0400000004000400ULL, 0x0400000104000400ULL, +0x0400000000040400ULL, 0x0400000100040400ULL, 0x0400000004040400ULL, 0x0400000104040400ULL, +0x0400000000000004ULL, 0x0400000100000004ULL, 0x0400000004000004ULL, 0x0400000104000004ULL, +0x0400000000040004ULL, 0x0400000100040004ULL, 0x0400000004040004ULL, 0x0400000104040004ULL, +0x0400000000000404ULL, 0x0400000100000404ULL, 0x0400000004000404ULL, 0x0400000104000404ULL, +0x0400000000040404ULL, 0x0400000100040404ULL, 0x0400000004040404ULL, 0x0400000104040404ULL, +0x0004000000000000ULL, 0x0004000100000000ULL, 0x0004000004000000ULL, 0x0004000104000000ULL, +0x0004000000040000ULL, 0x0004000100040000ULL, 0x0004000004040000ULL, 0x0004000104040000ULL, +0x0004000000000400ULL, 0x0004000100000400ULL, 0x0004000004000400ULL, 0x0004000104000400ULL, +0x0004000000040400ULL, 0x0004000100040400ULL, 0x0004000004040400ULL, 0x0004000104040400ULL, +0x0004000000000004ULL, 0x0004000100000004ULL, 0x0004000004000004ULL, 0x0004000104000004ULL, +0x0004000000040004ULL, 0x0004000100040004ULL, 0x0004000004040004ULL, 0x0004000104040004ULL, +0x0004000000000404ULL, 0x0004000100000404ULL, 0x0004000004000404ULL, 0x0004000104000404ULL, +0x0004000000040404ULL, 0x0004000100040404ULL, 0x0004000004040404ULL, 0x0004000104040404ULL, +0x0404000000000000ULL, 0x0404000100000000ULL, 0x0404000004000000ULL, 0x0404000104000000ULL, +0x0404000000040000ULL, 0x0404000100040000ULL, 0x0404000004040000ULL, 0x0404000104040000ULL, +0x0404000000000400ULL, 0x0404000100000400ULL, 0x0404000004000400ULL, 0x0404000104000400ULL, +0x0404000000040400ULL, 0x0404000100040400ULL, 0x0404000004040400ULL, 0x0404000104040400ULL, +0x0404000000000004ULL, 0x0404000100000004ULL, 0x0404000004000004ULL, 0x0404000104000004ULL, +0x0404000000040004ULL, 0x0404000100040004ULL, 0x0404000004040004ULL, 0x0404000104040004ULL, +0x0404000000000404ULL, 0x0404000100000404ULL, 0x0404000004000404ULL, 0x0404000104000404ULL, +0x0404000000040404ULL, 0x0404000100040404ULL, 0x0404000004040404ULL, 0x0404000104040404ULL, +0x0000040000000000ULL, 0x0000040100000000ULL, 0x0000040004000000ULL, 0x0000040104000000ULL, +0x0000040000040000ULL, 0x0000040100040000ULL, 0x0000040004040000ULL, 0x0000040104040000ULL, +0x0000040000000400ULL, 0x0000040100000400ULL, 0x0000040004000400ULL, 0x0000040104000400ULL, +0x0000040000040400ULL, 0x0000040100040400ULL, 0x0000040004040400ULL, 0x0000040104040400ULL, +0x0000040000000004ULL, 0x0000040100000004ULL, 0x0000040004000004ULL, 0x0000040104000004ULL, +0x0000040000040004ULL, 0x0000040100040004ULL, 0x0000040004040004ULL, 0x0000040104040004ULL, +0x0000040000000404ULL, 0x0000040100000404ULL, 0x0000040004000404ULL, 0x0000040104000404ULL, +0x0000040000040404ULL, 0x0000040100040404ULL, 0x0000040004040404ULL, 0x0000040104040404ULL, +0x0400040000000000ULL, 0x0400040100000000ULL, 0x0400040004000000ULL, 0x0400040104000000ULL, +0x0400040000040000ULL, 0x0400040100040000ULL, 0x0400040004040000ULL, 0x0400040104040000ULL, +0x0400040000000400ULL, 0x0400040100000400ULL, 0x0400040004000400ULL, 0x0400040104000400ULL, +0x0400040000040400ULL, 0x0400040100040400ULL, 0x0400040004040400ULL, 0x0400040104040400ULL, +0x0400040000000004ULL, 0x0400040100000004ULL, 0x0400040004000004ULL, 0x0400040104000004ULL, +0x0400040000040004ULL, 0x0400040100040004ULL, 0x0400040004040004ULL, 0x0400040104040004ULL, +0x0400040000000404ULL, 0x0400040100000404ULL, 0x0400040004000404ULL, 0x0400040104000404ULL, +0x0400040000040404ULL, 0x0400040100040404ULL, 0x0400040004040404ULL, 0x0400040104040404ULL, +0x0004040000000000ULL, 0x0004040100000000ULL, 0x0004040004000000ULL, 0x0004040104000000ULL, +0x0004040000040000ULL, 0x0004040100040000ULL, 0x0004040004040000ULL, 0x0004040104040000ULL, +0x0004040000000400ULL, 0x0004040100000400ULL, 0x0004040004000400ULL, 0x0004040104000400ULL, +0x0004040000040400ULL, 0x0004040100040400ULL, 0x0004040004040400ULL, 0x0004040104040400ULL, +0x0004040000000004ULL, 0x0004040100000004ULL, 0x0004040004000004ULL, 0x0004040104000004ULL, +0x0004040000040004ULL, 0x0004040100040004ULL, 0x0004040004040004ULL, 0x0004040104040004ULL, +0x0004040000000404ULL, 0x0004040100000404ULL, 0x0004040004000404ULL, 0x0004040104000404ULL, +0x0004040000040404ULL, 0x0004040100040404ULL, 0x0004040004040404ULL, 0x0004040104040404ULL, +0x0404040000000000ULL, 0x0404040100000000ULL, 0x0404040004000000ULL, 0x0404040104000000ULL, +0x0404040000040000ULL, 0x0404040100040000ULL, 0x0404040004040000ULL, 0x0404040104040000ULL, +0x0404040000000400ULL, 0x0404040100000400ULL, 0x0404040004000400ULL, 0x0404040104000400ULL, +0x0404040000040400ULL, 0x0404040100040400ULL, 0x0404040004040400ULL, 0x0404040104040400ULL, +0x0404040000000004ULL, 0x0404040100000004ULL, 0x0404040004000004ULL, 0x0404040104000004ULL, +0x0404040000040004ULL, 0x0404040100040004ULL, 0x0404040004040004ULL, 0x0404040104040004ULL, +0x0404040000000404ULL, 0x0404040100000404ULL, 0x0404040004000404ULL, 0x0404040104000404ULL, +0x0404040000040404ULL, 0x0404040100040404ULL, 0x0404040004040404ULL, 0x0404040104040404ULL }; + +const u64bit DES_FPTAB2[256] = { +0x0000000000000000ULL, 0x0000004000000000ULL, 0x0000000001000000ULL, 0x0000004001000000ULL, +0x0000000000010000ULL, 0x0000004000010000ULL, 0x0000000001010000ULL, 0x0000004001010000ULL, +0x0000000000000100ULL, 0x0000004000000100ULL, 0x0000000001000100ULL, 0x0000004001000100ULL, +0x0000000000010100ULL, 0x0000004000010100ULL, 0x0000000001010100ULL, 0x0000004001010100ULL, +0x0000000000000001ULL, 0x0000004000000001ULL, 0x0000000001000001ULL, 0x0000004001000001ULL, +0x0000000000010001ULL, 0x0000004000010001ULL, 0x0000000001010001ULL, 0x0000004001010001ULL, +0x0000000000000101ULL, 0x0000004000000101ULL, 0x0000000001000101ULL, 0x0000004001000101ULL, +0x0000000000010101ULL, 0x0000004000010101ULL, 0x0000000001010101ULL, 0x0000004001010101ULL, +0x0100000000000000ULL, 0x0100004000000000ULL, 0x0100000001000000ULL, 0x0100004001000000ULL, +0x0100000000010000ULL, 0x0100004000010000ULL, 0x0100000001010000ULL, 0x0100004001010000ULL, +0x0100000000000100ULL, 0x0100004000000100ULL, 0x0100000001000100ULL, 0x0100004001000100ULL, +0x0100000000010100ULL, 0x0100004000010100ULL, 0x0100000001010100ULL, 0x0100004001010100ULL, +0x0100000000000001ULL, 0x0100004000000001ULL, 0x0100000001000001ULL, 0x0100004001000001ULL, +0x0100000000010001ULL, 0x0100004000010001ULL, 0x0100000001010001ULL, 0x0100004001010001ULL, +0x0100000000000101ULL, 0x0100004000000101ULL, 0x0100000001000101ULL, 0x0100004001000101ULL, +0x0100000000010101ULL, 0x0100004000010101ULL, 0x0100000001010101ULL, 0x0100004001010101ULL, +0x0001000000000000ULL, 0x0001004000000000ULL, 0x0001000001000000ULL, 0x0001004001000000ULL, +0x0001000000010000ULL, 0x0001004000010000ULL, 0x0001000001010000ULL, 0x0001004001010000ULL, +0x0001000000000100ULL, 0x0001004000000100ULL, 0x0001000001000100ULL, 0x0001004001000100ULL, +0x0001000000010100ULL, 0x0001004000010100ULL, 0x0001000001010100ULL, 0x0001004001010100ULL, +0x0001000000000001ULL, 0x0001004000000001ULL, 0x0001000001000001ULL, 0x0001004001000001ULL, +0x0001000000010001ULL, 0x0001004000010001ULL, 0x0001000001010001ULL, 0x0001004001010001ULL, +0x0001000000000101ULL, 0x0001004000000101ULL, 0x0001000001000101ULL, 0x0001004001000101ULL, +0x0001000000010101ULL, 0x0001004000010101ULL, 0x0001000001010101ULL, 0x0001004001010101ULL, +0x0101000000000000ULL, 0x0101004000000000ULL, 0x0101000001000000ULL, 0x0101004001000000ULL, +0x0101000000010000ULL, 0x0101004000010000ULL, 0x0101000001010000ULL, 0x0101004001010000ULL, +0x0101000000000100ULL, 0x0101004000000100ULL, 0x0101000001000100ULL, 0x0101004001000100ULL, +0x0101000000010100ULL, 0x0101004000010100ULL, 0x0101000001010100ULL, 0x0101004001010100ULL, +0x0101000000000001ULL, 0x0101004000000001ULL, 0x0101000001000001ULL, 0x0101004001000001ULL, +0x0101000000010001ULL, 0x0101004000010001ULL, 0x0101000001010001ULL, 0x0101004001010001ULL, +0x0101000000000101ULL, 0x0101004000000101ULL, 0x0101000001000101ULL, 0x0101004001000101ULL, +0x0101000000010101ULL, 0x0101004000010101ULL, 0x0101000001010101ULL, 0x0101004001010101ULL, +0x0000010000000000ULL, 0x0000014000000000ULL, 0x0000010001000000ULL, 0x0000014001000000ULL, +0x0000010000010000ULL, 0x0000014000010000ULL, 0x0000010001010000ULL, 0x0000014001010000ULL, +0x0000010000000100ULL, 0x0000014000000100ULL, 0x0000010001000100ULL, 0x0000014001000100ULL, +0x0000010000010100ULL, 0x0000014000010100ULL, 0x0000010001010100ULL, 0x0000014001010100ULL, +0x0000010000000001ULL, 0x0000014000000001ULL, 0x0000010001000001ULL, 0x0000014001000001ULL, +0x0000010000010001ULL, 0x0000014000010001ULL, 0x0000010001010001ULL, 0x0000014001010001ULL, +0x0000010000000101ULL, 0x0000014000000101ULL, 0x0000010001000101ULL, 0x0000014001000101ULL, +0x0000010000010101ULL, 0x0000014000010101ULL, 0x0000010001010101ULL, 0x0000014001010101ULL, +0x0100010000000000ULL, 0x0100014000000000ULL, 0x0100010001000000ULL, 0x0100014001000000ULL, +0x0100010000010000ULL, 0x0100014000010000ULL, 0x0100010001010000ULL, 0x0100014001010000ULL, +0x0100010000000100ULL, 0x0100014000000100ULL, 0x0100010001000100ULL, 0x0100014001000100ULL, +0x0100010000010100ULL, 0x0100014000010100ULL, 0x0100010001010100ULL, 0x0100014001010100ULL, +0x0100010000000001ULL, 0x0100014000000001ULL, 0x0100010001000001ULL, 0x0100014001000001ULL, +0x0100010000010001ULL, 0x0100014000010001ULL, 0x0100010001010001ULL, 0x0100014001010001ULL, +0x0100010000000101ULL, 0x0100014000000101ULL, 0x0100010001000101ULL, 0x0100014001000101ULL, +0x0100010000010101ULL, 0x0100014000010101ULL, 0x0100010001010101ULL, 0x0100014001010101ULL, +0x0001010000000000ULL, 0x0001014000000000ULL, 0x0001010001000000ULL, 0x0001014001000000ULL, +0x0001010000010000ULL, 0x0001014000010000ULL, 0x0001010001010000ULL, 0x0001014001010000ULL, +0x0001010000000100ULL, 0x0001014000000100ULL, 0x0001010001000100ULL, 0x0001014001000100ULL, +0x0001010000010100ULL, 0x0001014000010100ULL, 0x0001010001010100ULL, 0x0001014001010100ULL, +0x0001010000000001ULL, 0x0001014000000001ULL, 0x0001010001000001ULL, 0x0001014001000001ULL, +0x0001010000010001ULL, 0x0001014000010001ULL, 0x0001010001010001ULL, 0x0001014001010001ULL, +0x0001010000000101ULL, 0x0001014000000101ULL, 0x0001010001000101ULL, 0x0001014001000101ULL, +0x0001010000010101ULL, 0x0001014000010101ULL, 0x0001010001010101ULL, 0x0001014001010101ULL, +0x0101010000000000ULL, 0x0101014000000000ULL, 0x0101010001000000ULL, 0x0101014001000000ULL, +0x0101010000010000ULL, 0x0101014000010000ULL, 0x0101010001010000ULL, 0x0101014001010000ULL, +0x0101010000000100ULL, 0x0101014000000100ULL, 0x0101010001000100ULL, 0x0101014001000100ULL, +0x0101010000010100ULL, 0x0101014000010100ULL, 0x0101010001010100ULL, 0x0101014001010100ULL, +0x0101010000000001ULL, 0x0101014000000001ULL, 0x0101010001000001ULL, 0x0101014001000001ULL, +0x0101010000010001ULL, 0x0101014000010001ULL, 0x0101010001010001ULL, 0x0101014001010001ULL, +0x0101010000000101ULL, 0x0101014000000101ULL, 0x0101010001000101ULL, 0x0101014001000101ULL, +0x0101010000010101ULL, 0x0101014000010101ULL, 0x0101010001010101ULL, 0x0101014001010101ULL }; + +} +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* DESX Encryption +*/ +void DESX::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, &K1[0], BLOCK_SIZE); + des.encrypt(out); + xor_buf(out, &K2[0], BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Decryption +*/ +void DESX::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, &K2[0], BLOCK_SIZE); + des.decrypt(out); + xor_buf(out, &K1[0], BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Key Schedule +*/ +void DESX::key_schedule(const byte key[], size_t) + { + K1.copy(key, 8); + des.set_key(key + 8, 8); + K2.copy(key + 16, 8); + } + +} +/* +* GOST 28147-89 +* (C) 1999-2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +byte GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const + { + byte x = sboxes[4 * col + (row / 2)]; + + return (row % 2 == 0) ? (x >> 4) : (x & 0x0F); + } + +GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : name(n) + { + // Encoded in the packed fromat from RFC 4357 + + // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0) + static const byte GOST_R_3411_TEST_PARAMS[64] = { + 0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A, + 0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38, + 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62, + 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3, + 0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C, + 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC }; + + // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1) + static const byte GOST_R_3411_CRYPTOPRO_PARAMS[64] = { + 0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42, + 0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F, + 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1, + 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87, + 0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE, + 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC }; + + if(name == "R3411_94_TestParam") + sboxes = GOST_R_3411_TEST_PARAMS; + else if(name == "R3411_CryptoPro") + sboxes = GOST_R_3411_CRYPTOPRO_PARAMS; + else + throw Invalid_Argument("GOST_28147_89_Params: Unknown " + name); + } + +/* +* GOST Constructor +*/ +GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) : + SBOX(1024), EK(8) + { + // Convert the parallel 4x4 sboxes into larger word-based sboxes + for(size_t i = 0; i != 4; ++i) + for(size_t j = 0; j != 256; ++j) + { + const u32bit T = (param.sbox_entry(2*i , j % 16)) | + (param.sbox_entry(2*i+1, j / 16) << 4); + SBOX[256*i+j] = rotate_left(T, (11+8*i) % 32); + } + } + +std::string GOST_28147_89::name() const + { + /* + 'Guess' the right name for the sbox on the basis of the values. + This would need to be updated if support for other sbox parameters + is added. Preferably, we would just store the string value in the + constructor, but can't break binary compat. + */ + std::string sbox_name = ""; + if(SBOX[0] == 0x00072000) + sbox_name = "R3411_94_TestParam"; + else if(SBOX[0] == 0x0002D000) + sbox_name = "R3411_CryptoPro"; + else + throw Internal_Error("GOST-28147 unrecognized sbox value"); + + return "GOST-28147-89(" + sbox_name + ")"; + } + +/* +* Two rounds of GOST +*/ +#define GOST_2ROUND(N1, N2, R1, R2) \ + do { \ + u32bit T0 = N1 + EK[R1]; \ + N2 ^= SBOX[get_byte(3, T0)] | \ + SBOX[get_byte(2, T0)+256] | \ + SBOX[get_byte(1, T0)+512] | \ + SBOX[get_byte(0, T0)+768]; \ + \ + u32bit T1 = N2 + EK[R2]; \ + N1 ^= SBOX[get_byte(3, T1)] | \ + SBOX[get_byte(2, T1)+256] | \ + SBOX[get_byte(1, T1)+512] | \ + SBOX[get_byte(0, T1)+768]; \ + } while(0) + +/* +* GOST Encryption +*/ +void GOST_28147_89::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit N1 = load_le(in, 0); + u32bit N2 = load_le(in, 1); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + } + + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + + store_le(out, N2, N1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Decryption +*/ +void GOST_28147_89::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit N1 = load_le(in, 0); + u32bit N2 = load_le(in, 1); + + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + } + + store_le(out, N2, N1); + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Key Schedule +*/ +void GOST_28147_89::key_schedule(const byte key[], size_t) + { + for(size_t i = 0; i != 8; ++i) + EK[i] = load_le(key, i); + } + +} +/* +* IDEA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Multiplication modulo 65537 +*/ +inline u16bit mul(u16bit x, u16bit y) + { + const u32bit P = static_cast(x) * y; + + // P ? 0xFFFF : 0 + const u16bit P_mask = !P - 1; + + const u32bit P_hi = P >> 16; + const u32bit P_lo = P & 0xFFFF; + + const u16bit r_1 = (P_lo - P_hi) + (P_lo < P_hi); + const u16bit r_2 = 1 - x - y; + + return (r_1 & P_mask) | (r_2 & ~P_mask); + } + +/* +* Find multiplicative inverses modulo 65537 +* +* 65537 is prime; thus Fermat's little theorem tells us that +* x^65537 == x modulo 65537, which means +* x^(65537-2) == x^-1 modulo 65537 since +* x^(65537-2) * x == 1 mod 65537 +* +* Do the exponentiation with a basic square and multiply: all bits are +* of exponent are 1 so we always multiply +*/ +u16bit mul_inv(u16bit x) + { + u16bit y = x; + + for(size_t i = 0; i != 15; ++i) + { + y = mul(y, y); // square + y = mul(y, x); + } + + return y; + } + +/** +* IDEA is involutional, depending only on the key schedule +*/ +void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) + { + const size_t BLOCK_SIZE = 8; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit X1 = load_be(in, 0); + u16bit X2 = load_be(in, 1); + u16bit X3 = load_be(in, 2); + u16bit X4 = load_be(in, 3); + + for(size_t j = 0; j != 8; ++j) + { + X1 = mul(X1, K[6*j+0]); + X2 += K[6*j+1]; + X3 += K[6*j+2]; + X4 = mul(X4, K[6*j+3]); + + u16bit T0 = X3; + X3 = mul(X3 ^ X1, K[6*j+4]); + + u16bit T1 = X2; + X2 = mul((X2 ^ X4) + X3, K[6*j+5]); + X3 += X2; + + X1 ^= X2; + X4 ^= X3; + X2 ^= T0; + X3 ^= T1; + } + + X1 = mul(X1, K[48]); + X2 += K[50]; + X3 += K[49]; + X4 = mul(X4, K[51]); + + store_be(out, X1, X3, X2, X4); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +} + +/* +* IDEA Encryption +*/ +void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + idea_op(in, out, blocks, &EK[0]); + } + +/* +* IDEA Decryption +*/ +void IDEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + idea_op(in, out, blocks, &DK[0]); + } + +/* +* IDEA Key Schedule +*/ +void IDEA::key_schedule(const byte key[], size_t) + { + for(size_t i = 0; i != 8; ++i) + EK[i] = load_be(key, i); + + for(size_t i = 1, j = 8, offset = 0; j != 52; i %= 8, ++i, ++j) + { + EK[i+7+offset] = static_cast((EK[(i % 8) + offset] << 9) | + (EK[((i+1) % 8) + offset] >> 7)); + offset += (i == 8) ? 8 : 0; + } + + DK[51] = mul_inv(EK[3]); + DK[50] = -EK[2]; + DK[49] = -EK[1]; + DK[48] = mul_inv(EK[0]); + + for(size_t i = 1, j = 4, counter = 47; i != 8; ++i, j += 6) + { + DK[counter--] = EK[j+1]; + DK[counter--] = EK[j]; + DK[counter--] = mul_inv(EK[j+5]); + DK[counter--] = -EK[j+3]; + DK[counter--] = -EK[j+4]; + DK[counter--] = mul_inv(EK[j+2]); + } + + DK[5] = EK[47]; + DK[4] = EK[46]; + DK[3] = mul_inv(EK[51]); + DK[2] = -EK[50]; + DK[1] = -EK[49]; + DK[0] = mul_inv(EK[48]); + } + +} +/* +* KASUMI +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* KASUMI S-Boxes +*/ +const byte KASUMI_SBOX_S7[128] = { + 0x36, 0x32, 0x3E, 0x38, 0x16, 0x22, 0x5E, 0x60, 0x26, 0x06, 0x3F, 0x5D, + 0x02, 0x12, 0x7B, 0x21, 0x37, 0x71, 0x27, 0x72, 0x15, 0x43, 0x41, 0x0C, + 0x2F, 0x49, 0x2E, 0x1B, 0x19, 0x6F, 0x7C, 0x51, 0x35, 0x09, 0x79, 0x4F, + 0x34, 0x3C, 0x3A, 0x30, 0x65, 0x7F, 0x28, 0x78, 0x68, 0x46, 0x47, 0x2B, + 0x14, 0x7A, 0x48, 0x3D, 0x17, 0x6D, 0x0D, 0x64, 0x4D, 0x01, 0x10, 0x07, + 0x52, 0x0A, 0x69, 0x62, 0x75, 0x74, 0x4C, 0x0B, 0x59, 0x6A, 0x00, 0x7D, + 0x76, 0x63, 0x56, 0x45, 0x1E, 0x39, 0x7E, 0x57, 0x70, 0x33, 0x11, 0x05, + 0x5F, 0x0E, 0x5A, 0x54, 0x5B, 0x08, 0x23, 0x67, 0x20, 0x61, 0x1C, 0x42, + 0x66, 0x1F, 0x1A, 0x2D, 0x4B, 0x04, 0x55, 0x5C, 0x25, 0x4A, 0x50, 0x31, + 0x44, 0x1D, 0x73, 0x2C, 0x40, 0x6B, 0x6C, 0x18, 0x6E, 0x53, 0x24, 0x4E, + 0x2A, 0x13, 0x0F, 0x29, 0x58, 0x77, 0x3B, 0x03 }; + +const u16bit KASUMI_SBOX_S9[512] = { + 0x00A7, 0x00EF, 0x00A1, 0x017B, 0x0187, 0x014E, 0x0009, 0x0152, 0x0026, + 0x00E2, 0x0030, 0x0166, 0x01C4, 0x0181, 0x005A, 0x018D, 0x00B7, 0x00FD, + 0x0093, 0x014B, 0x019F, 0x0154, 0x0033, 0x016A, 0x0132, 0x01F4, 0x0106, + 0x0052, 0x00D8, 0x009F, 0x0164, 0x00B1, 0x00AF, 0x00F1, 0x01E9, 0x0025, + 0x00CE, 0x0011, 0x0000, 0x014D, 0x002C, 0x00FE, 0x017A, 0x003A, 0x008F, + 0x00DC, 0x0051, 0x0190, 0x005F, 0x0003, 0x013B, 0x00F5, 0x0036, 0x00EB, + 0x00DA, 0x0195, 0x01D8, 0x0108, 0x00AC, 0x01EE, 0x0173, 0x0122, 0x018F, + 0x004C, 0x00A5, 0x00C5, 0x018B, 0x0079, 0x0101, 0x01E0, 0x01A7, 0x00D4, + 0x00F0, 0x001C, 0x01CE, 0x00B0, 0x0196, 0x01FB, 0x0120, 0x00DF, 0x01F5, + 0x0197, 0x00F9, 0x0109, 0x0059, 0x00BA, 0x00DD, 0x01AC, 0x00A4, 0x004A, + 0x01B8, 0x00C4, 0x01CA, 0x01A5, 0x015E, 0x00A3, 0x00E8, 0x009E, 0x0086, + 0x0162, 0x000D, 0x00FA, 0x01EB, 0x008E, 0x00BF, 0x0045, 0x00C1, 0x01A9, + 0x0098, 0x00E3, 0x016E, 0x0087, 0x0158, 0x012C, 0x0114, 0x00F2, 0x01B5, + 0x0140, 0x0071, 0x0116, 0x000B, 0x00F3, 0x0057, 0x013D, 0x0024, 0x005D, + 0x01F0, 0x001B, 0x01E7, 0x01BE, 0x01E2, 0x0029, 0x0044, 0x009C, 0x01C9, + 0x0083, 0x0146, 0x0193, 0x0153, 0x0014, 0x0027, 0x0073, 0x01BA, 0x007C, + 0x01DB, 0x0180, 0x01FC, 0x0035, 0x0070, 0x00AA, 0x01DF, 0x0097, 0x007E, + 0x00A9, 0x0049, 0x010C, 0x0117, 0x0141, 0x00A8, 0x016C, 0x016B, 0x0124, + 0x002E, 0x01F3, 0x0189, 0x0147, 0x0144, 0x0018, 0x01C8, 0x010B, 0x009D, + 0x01CC, 0x01E8, 0x01AA, 0x0135, 0x00E5, 0x01B7, 0x01FA, 0x00D0, 0x010F, + 0x015D, 0x0191, 0x01B2, 0x00EC, 0x0010, 0x00D1, 0x0167, 0x0034, 0x0038, + 0x0078, 0x00C7, 0x0115, 0x01D1, 0x01A0, 0x00FC, 0x011F, 0x00F6, 0x0006, + 0x0053, 0x0131, 0x01A4, 0x0159, 0x0099, 0x01F6, 0x0041, 0x003D, 0x00F4, + 0x011A, 0x00AD, 0x00DE, 0x01A2, 0x0043, 0x0182, 0x0170, 0x0105, 0x0065, + 0x01DC, 0x0123, 0x00C3, 0x01AE, 0x0031, 0x004F, 0x00A6, 0x014A, 0x0118, + 0x017F, 0x0175, 0x0080, 0x017E, 0x0198, 0x009B, 0x01EF, 0x016F, 0x0184, + 0x0112, 0x006B, 0x01CB, 0x01A1, 0x003E, 0x01C6, 0x0084, 0x00E1, 0x00CB, + 0x013C, 0x00EA, 0x000E, 0x012D, 0x005B, 0x01F7, 0x011E, 0x01A8, 0x00D3, + 0x015B, 0x0133, 0x008C, 0x0176, 0x0023, 0x0067, 0x007D, 0x01AB, 0x0013, + 0x00D6, 0x01C5, 0x0092, 0x01F2, 0x013A, 0x01BC, 0x00E6, 0x0100, 0x0149, + 0x00C6, 0x011D, 0x0032, 0x0074, 0x004E, 0x019A, 0x000A, 0x00CD, 0x01FE, + 0x00AB, 0x00E7, 0x002D, 0x008B, 0x01D3, 0x001D, 0x0056, 0x01F9, 0x0020, + 0x0048, 0x001A, 0x0156, 0x0096, 0x0139, 0x01EA, 0x01AF, 0x00EE, 0x019B, + 0x0145, 0x0095, 0x01D9, 0x0028, 0x0077, 0x00AE, 0x0163, 0x00B9, 0x00E9, + 0x0185, 0x0047, 0x01C0, 0x0111, 0x0174, 0x0037, 0x006E, 0x00B2, 0x0142, + 0x000C, 0x01D5, 0x0188, 0x0171, 0x00BE, 0x0001, 0x006D, 0x0177, 0x0089, + 0x00B5, 0x0058, 0x004B, 0x0134, 0x0104, 0x01E4, 0x0062, 0x0110, 0x0172, + 0x0113, 0x019C, 0x006F, 0x0150, 0x013E, 0x0004, 0x01F8, 0x01EC, 0x0103, + 0x0130, 0x004D, 0x0151, 0x01B3, 0x0015, 0x0165, 0x012F, 0x014C, 0x01E3, + 0x0012, 0x002F, 0x0055, 0x0019, 0x01F1, 0x01DA, 0x0121, 0x0064, 0x010D, + 0x0128, 0x01DE, 0x010E, 0x006A, 0x001F, 0x0068, 0x01B1, 0x0054, 0x019E, + 0x01E6, 0x018A, 0x0060, 0x0063, 0x009A, 0x01FF, 0x0094, 0x019D, 0x0169, + 0x0199, 0x00FF, 0x00A2, 0x00D7, 0x012E, 0x00C9, 0x010A, 0x015F, 0x0157, + 0x0090, 0x01B9, 0x016D, 0x006C, 0x012A, 0x00FB, 0x0022, 0x00B6, 0x01FD, + 0x008A, 0x00D2, 0x014F, 0x0085, 0x0137, 0x0160, 0x0148, 0x008D, 0x018C, + 0x015A, 0x007B, 0x013F, 0x01C2, 0x0119, 0x01AD, 0x00E4, 0x01BB, 0x01E1, + 0x005C, 0x0194, 0x01E5, 0x01A6, 0x00F8, 0x0129, 0x0017, 0x00D5, 0x0082, + 0x01D2, 0x0016, 0x00D9, 0x011B, 0x0046, 0x0126, 0x0168, 0x01A3, 0x007F, + 0x0138, 0x0179, 0x0007, 0x01D4, 0x00C2, 0x0002, 0x0075, 0x0127, 0x01CF, + 0x0102, 0x00E0, 0x01BF, 0x00F7, 0x00BB, 0x0050, 0x018E, 0x011C, 0x0161, + 0x0069, 0x0186, 0x012B, 0x01D7, 0x01D6, 0x00B8, 0x0039, 0x00C8, 0x015C, + 0x003F, 0x00CC, 0x00BC, 0x0021, 0x01C3, 0x0061, 0x001E, 0x0136, 0x00DB, + 0x005E, 0x00A0, 0x0081, 0x01ED, 0x0040, 0x00B3, 0x0107, 0x0066, 0x00BD, + 0x00CF, 0x0072, 0x0192, 0x01B6, 0x01DD, 0x0183, 0x007A, 0x00C0, 0x002A, + 0x017D, 0x0005, 0x0091, 0x0076, 0x00B4, 0x01C1, 0x0125, 0x0143, 0x0088, + 0x017C, 0x002B, 0x0042, 0x003C, 0x01C7, 0x0155, 0x01BD, 0x00CA, 0x01B0, + 0x0008, 0x00ED, 0x000F, 0x0178, 0x01B4, 0x01D0, 0x003B, 0x01CD }; + +/* +* KASUMI FI Function +*/ +u16bit FI(u16bit I, u16bit K) + { + u16bit D9 = (I >> 7); + byte D7 = (I & 0x7F); + D9 = KASUMI_SBOX_S9[D9] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + + D7 ^= (K >> 9); + D9 = KASUMI_SBOX_S9[D9 ^ (K & 0x1FF)] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + return (D7 << 9) | D9; + } + +} + +/* +* KASUMI Encryption +*/ +void KASUMI::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const u16bit* K = &EK[8*j]; + + u16bit R = B1 ^ (rotate_left(B0, 1) & K[0]); + u16bit L = B0 ^ (rotate_left(R, 1) | K[1]); + + L = FI(L ^ K[ 2], K[ 3]) ^ R; + R = FI(R ^ K[ 4], K[ 5]) ^ L; + L = FI(L ^ K[ 6], K[ 7]) ^ R; + + R = B2 ^= R; + L = B3 ^= L; + + R = FI(R ^ K[10], K[11]) ^ L; + L = FI(L ^ K[12], K[13]) ^ R; + R = FI(R ^ K[14], K[15]) ^ L; + + R ^= (rotate_left(L, 1) & K[8]); + L ^= (rotate_left(R, 1) | K[9]); + + B0 ^= L; + B1 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Decryption +*/ +void KASUMI::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const u16bit* K = &EK[8*(6-j)]; + + u16bit L = B2, R = B3; + + L = FI(L ^ K[10], K[11]) ^ R; + R = FI(R ^ K[12], K[13]) ^ L; + L = FI(L ^ K[14], K[15]) ^ R; + + L ^= (rotate_left(R, 1) & K[8]); + R ^= (rotate_left(L, 1) | K[9]); + + R = B0 ^= R; + L = B1 ^= L; + + L ^= (rotate_left(R, 1) & K[0]); + R ^= (rotate_left(L, 1) | K[1]); + + R = FI(R ^ K[2], K[3]) ^ L; + L = FI(L ^ K[4], K[5]) ^ R; + R = FI(R ^ K[6], K[7]) ^ L; + + B2 ^= L; + B3 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Key Schedule +*/ +void KASUMI::key_schedule(const byte key[], size_t) + { + static const u16bit RC[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, + 0xFEDC, 0xBA98, 0x7654, 0x3210 }; + + SecureVector K(16); + for(size_t i = 0; i != 8; ++i) + { + K[i] = load_be(key, i); + K[i+8] = K[i] ^ RC[i]; + } + + for(size_t i = 0; i != 8; ++i) + { + EK[8*i ] = rotate_left(K[(i+0) % 8 ], 2); + EK[8*i+1] = rotate_left(K[(i+2) % 8 + 8], 1); + EK[8*i+2] = rotate_left(K[(i+1) % 8 ], 5); + EK[8*i+3] = K[(i+4) % 8 + 8]; + EK[8*i+4] = rotate_left(K[(i+5) % 8 ], 8); + EK[8*i+5] = K[(i+3) % 8 + 8]; + EK[8*i+6] = rotate_left(K[(i+6) % 8 ], 13); + EK[8*i+7] = K[(i+7) % 8 + 8]; + } + } + +} +/* +* Lion +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Lion Encryption +*/ +void Lion::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + SecureVector buffer_vec(LEFT_SIZE); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, &key1[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + hash->update(out + LEFT_SIZE, RIGHT_SIZE); + hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, &key2[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Lion Decryption +*/ +void Lion::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + SecureVector buffer_vec(LEFT_SIZE); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, &key2[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + hash->update(out + LEFT_SIZE, RIGHT_SIZE); + hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, &key1[0], LEFT_SIZE); + cipher->set_key(buffer, LEFT_SIZE); + cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Lion Key Schedule +*/ +void Lion::key_schedule(const byte key[], size_t length) + { + clear(); + + key1.copy(key, length / 2); + key2.copy(key + length / 2, length / 2); + } + +/* +* Return the name of this type +*/ +std::string Lion::name() const + { + return "Lion(" + hash->name() + "," + + cipher->name() + "," + + to_string(BLOCK_SIZE) + ")"; + } + +/* +* Return a clone of this object +*/ +BlockCipher* Lion::clone() const + { + return new Lion(hash->clone(), cipher->clone(), BLOCK_SIZE); + } + +/* +* Clear memory of sensitive data +*/ +void Lion::clear() + { + hash->clear(); + cipher->clear(); + zeroise(key1); + zeroise(key2); + } + +/* +* Lion Constructor +*/ +Lion::Lion(HashFunction* hash_in, StreamCipher* sc_in, size_t block_len) : + BLOCK_SIZE(std::max(2*hash_in->output_length() + 1, block_len)), + LEFT_SIZE(hash_in->output_length()), + RIGHT_SIZE(BLOCK_SIZE - LEFT_SIZE), + hash(hash_in), + cipher(sc_in) + { + if(2*LEFT_SIZE + 1 > BLOCK_SIZE) + throw Invalid_Argument(name() + ": Chosen block size is too small"); + + if(!cipher->valid_keylength(LEFT_SIZE)) + throw Invalid_Argument(name() + ": This stream/hash combo is invalid"); + + key1.resize(LEFT_SIZE); + key2.resize(LEFT_SIZE); + } + +} +/* +* Luby-Rackoff +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Luby-Rackoff Encryption +*/ +void LubyRackoff::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t len = hash->output_length(); + + SecureVector buffer_vec(len); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + hash->update(K1); + hash->update(in, len); + hash->final(buffer); + xor_buf(out + len, in + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, in, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, buffer, len); + + in += 2 * len; + out += 2 * len; + } + } + +/* +* Luby-Rackoff Decryption +*/ +void LubyRackoff::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t len = hash->output_length(); + + SecureVector buffer_vec(len); + byte* buffer = &buffer_vec[0]; + + for(size_t i = 0; i != blocks; ++i) + { + hash->update(K2); + hash->update(in + len, len); + hash->final(buffer); + xor_buf(out, in, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, in + len, buffer, len); + + hash->update(K2); + hash->update(out + len, len); + hash->final(buffer); + xor_buf(out, buffer, len); + + hash->update(K1); + hash->update(out, len); + hash->final(buffer); + xor_buf(out + len, buffer, len); + + in += 2 * len; + out += 2 * len; + } + } + +/* +* Luby-Rackoff Key Schedule +*/ +void LubyRackoff::key_schedule(const byte key[], size_t length) + { + K1.resize(length / 2); + K2.resize(length / 2); + copy_mem(&K1[0], key , length / 2); + copy_mem(&K2[0], key + length / 2, length / 2); + } + +/* +* Clear memory of sensitive data +*/ +void LubyRackoff::clear() + { + zeroise(K1); + zeroise(K2); + hash->clear(); + } + +/* +* Return a clone of this object +*/ +BlockCipher* LubyRackoff::clone() const + { + return new LubyRackoff(hash->clone()); + } + +/* +* Return the name of this type +*/ +std::string LubyRackoff::name() const + { + return "Luby-Rackoff(" + hash->name() + ")"; + } + +/* +* Luby-Rackoff Constructor +*/ +LubyRackoff::LubyRackoff(HashFunction* h) : hash(h) + { + } + +} +/* +* MARS +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/** +* The MARS sbox +*/ +const u32bit SBOX[512] = { + 0x09D0C479, 0x28C8FFE0, 0x84AA6C39, 0x9DAD7287, 0x7DFF9BE3, 0xD4268361, + 0xC96DA1D4, 0x7974CC93, 0x85D0582E, 0x2A4B5705, 0x1CA16A62, 0xC3BD279D, + 0x0F1F25E5, 0x5160372F, 0xC695C1FB, 0x4D7FF1E4, 0xAE5F6BF4, 0x0D72EE46, + 0xFF23DE8A, 0xB1CF8E83, 0xF14902E2, 0x3E981E42, 0x8BF53EB6, 0x7F4BF8AC, + 0x83631F83, 0x25970205, 0x76AFE784, 0x3A7931D4, 0x4F846450, 0x5C64C3F6, + 0x210A5F18, 0xC6986A26, 0x28F4E826, 0x3A60A81C, 0xD340A664, 0x7EA820C4, + 0x526687C5, 0x7EDDD12B, 0x32A11D1D, 0x9C9EF086, 0x80F6E831, 0xAB6F04AD, + 0x56FB9B53, 0x8B2E095C, 0xB68556AE, 0xD2250B0D, 0x294A7721, 0xE21FB253, + 0xAE136749, 0xE82AAE86, 0x93365104, 0x99404A66, 0x78A784DC, 0xB69BA84B, + 0x04046793, 0x23DB5C1E, 0x46CAE1D6, 0x2FE28134, 0x5A223942, 0x1863CD5B, + 0xC190C6E3, 0x07DFB846, 0x6EB88816, 0x2D0DCC4A, 0xA4CCAE59, 0x3798670D, + 0xCBFA9493, 0x4F481D45, 0xEAFC8CA8, 0xDB1129D6, 0xB0449E20, 0x0F5407FB, + 0x6167D9A8, 0xD1F45763, 0x4DAA96C3, 0x3BEC5958, 0xABABA014, 0xB6CCD201, + 0x38D6279F, 0x02682215, 0x8F376CD5, 0x092C237E, 0xBFC56593, 0x32889D2C, + 0x854B3E95, 0x05BB9B43, 0x7DCD5DCD, 0xA02E926C, 0xFAE527E5, 0x36A1C330, + 0x3412E1AE, 0xF257F462, 0x3C4F1D71, 0x30A2E809, 0x68E5F551, 0x9C61BA44, + 0x5DED0AB8, 0x75CE09C8, 0x9654F93E, 0x698C0CCA, 0x243CB3E4, 0x2B062B97, + 0x0F3B8D9E, 0x00E050DF, 0xFC5D6166, 0xE35F9288, 0xC079550D, 0x0591AEE8, + 0x8E531E74, 0x75FE3578, 0x2F6D829A, 0xF60B21AE, 0x95E8EB8D, 0x6699486B, + 0x901D7D9B, 0xFD6D6E31, 0x1090ACEF, 0xE0670DD8, 0xDAB2E692, 0xCD6D4365, + 0xE5393514, 0x3AF345F0, 0x6241FC4D, 0x460DA3A3, 0x7BCF3729, 0x8BF1D1E0, + 0x14AAC070, 0x1587ED55, 0x3AFD7D3E, 0xD2F29E01, 0x29A9D1F6, 0xEFB10C53, + 0xCF3B870F, 0xB414935C, 0x664465ED, 0x024ACAC7, 0x59A744C1, 0x1D2936A7, + 0xDC580AA6, 0xCF574CA8, 0x040A7A10, 0x6CD81807, 0x8A98BE4C, 0xACCEA063, + 0xC33E92B5, 0xD1E0E03D, 0xB322517E, 0x2092BD13, 0x386B2C4A, 0x52E8DD58, + 0x58656DFB, 0x50820371, 0x41811896, 0xE337EF7E, 0xD39FB119, 0xC97F0DF6, + 0x68FEA01B, 0xA150A6E5, 0x55258962, 0xEB6FF41B, 0xD7C9CD7A, 0xA619CD9E, + 0xBCF09576, 0x2672C073, 0xF003FB3C, 0x4AB7A50B, 0x1484126A, 0x487BA9B1, + 0xA64FC9C6, 0xF6957D49, 0x38B06A75, 0xDD805FCD, 0x63D094CF, 0xF51C999E, + 0x1AA4D343, 0xB8495294, 0xCE9F8E99, 0xBFFCD770, 0xC7C275CC, 0x378453A7, + 0x7B21BE33, 0x397F41BD, 0x4E94D131, 0x92CC1F98, 0x5915EA51, 0x99F861B7, + 0xC9980A88, 0x1D74FD5F, 0xB0A495F8, 0x614DEED0, 0xB5778EEA, 0x5941792D, + 0xFA90C1F8, 0x33F824B4, 0xC4965372, 0x3FF6D550, 0x4CA5FEC0, 0x8630E964, + 0x5B3FBBD6, 0x7DA26A48, 0xB203231A, 0x04297514, 0x2D639306, 0x2EB13149, + 0x16A45272, 0x532459A0, 0x8E5F4872, 0xF966C7D9, 0x07128DC0, 0x0D44DB62, + 0xAFC8D52D, 0x06316131, 0xD838E7CE, 0x1BC41D00, 0x3A2E8C0F, 0xEA83837E, + 0xB984737D, 0x13BA4891, 0xC4F8B949, 0xA6D6ACB3, 0xA215CDCE, 0x8359838B, + 0x6BD1AA31, 0xF579DD52, 0x21B93F93, 0xF5176781, 0x187DFDDE, 0xE94AEB76, + 0x2B38FD54, 0x431DE1DA, 0xAB394825, 0x9AD3048F, 0xDFEA32AA, 0x659473E3, + 0x623F7863, 0xF3346C59, 0xAB3AB685, 0x3346A90B, 0x6B56443E, 0xC6DE01F8, + 0x8D421FC0, 0x9B0ED10C, 0x88F1A1E9, 0x54C1F029, 0x7DEAD57B, 0x8D7BA426, + 0x4CF5178A, 0x551A7CCA, 0x1A9A5F08, 0xFCD651B9, 0x25605182, 0xE11FC6C3, + 0xB6FD9676, 0x337B3027, 0xB7C8EB14, 0x9E5FD030, 0x6B57E354, 0xAD913CF7, + 0x7E16688D, 0x58872A69, 0x2C2FC7DF, 0xE389CCC6, 0x30738DF1, 0x0824A734, + 0xE1797A8B, 0xA4A8D57B, 0x5B5D193B, 0xC8A8309B, 0x73F9A978, 0x73398D32, + 0x0F59573E, 0xE9DF2B03, 0xE8A5B6C8, 0x848D0704, 0x98DF93C2, 0x720A1DC3, + 0x684F259A, 0x943BA848, 0xA6370152, 0x863B5EA3, 0xD17B978B, 0x6D9B58EF, + 0x0A700DD4, 0xA73D36BF, 0x8E6A0829, 0x8695BC14, 0xE35B3447, 0x933AC568, + 0x8894B022, 0x2F511C27, 0xDDFBCC3C, 0x006662B6, 0x117C83FE, 0x4E12B414, + 0xC2BCA766, 0x3A2FEC10, 0xF4562420, 0x55792E2A, 0x46F5D857, 0xCEDA25CE, + 0xC3601D3B, 0x6C00AB46, 0xEFAC9C28, 0xB3C35047, 0x611DFEE3, 0x257C3207, + 0xFDD58482, 0x3B14D84F, 0x23BECB64, 0xA075F3A3, 0x088F8EAD, 0x07ADF158, + 0x7796943C, 0xFACABF3D, 0xC09730CD, 0xF7679969, 0xDA44E9ED, 0x2C854C12, + 0x35935FA3, 0x2F057D9F, 0x690624F8, 0x1CB0BAFD, 0x7B0DBDC6, 0x810F23BB, + 0xFA929A1A, 0x6D969A17, 0x6742979B, 0x74AC7D05, 0x010E65C4, 0x86A3D963, + 0xF907B5A0, 0xD0042BD3, 0x158D7D03, 0x287A8255, 0xBBA8366F, 0x096EDC33, + 0x21916A7B, 0x77B56B86, 0x951622F9, 0xA6C5E650, 0x8CEA17D1, 0xCD8C62BC, + 0xA3D63433, 0x358A68FD, 0x0F9B9D3C, 0xD6AA295B, 0xFE33384A, 0xC000738E, + 0xCD67EB2F, 0xE2EB6DC2, 0x97338B02, 0x06C9F246, 0x419CF1AD, 0x2B83C045, + 0x3723F18A, 0xCB5B3089, 0x160BEAD7, 0x5D494656, 0x35F8A74B, 0x1E4E6C9E, + 0x000399BD, 0x67466880, 0xB4174831, 0xACF423B2, 0xCA815AB3, 0x5A6395E7, + 0x302A67C5, 0x8BDB446B, 0x108F8FA4, 0x10223EDA, 0x92B8B48B, 0x7F38D0EE, + 0xAB2701D4, 0x0262D415, 0xAF224A30, 0xB3D88ABA, 0xF8B2C3AF, 0xDAF7EF70, + 0xCC97D3B7, 0xE9614B6C, 0x2BAEBFF4, 0x70F687CF, 0x386C9156, 0xCE092EE5, + 0x01E87DA6, 0x6CE91E6A, 0xBB7BCC84, 0xC7922C20, 0x9D3B71FD, 0x060E41C6, + 0xD7590F15, 0x4E03BB47, 0x183C198E, 0x63EEB240, 0x2DDBF49A, 0x6D5CBA54, + 0x923750AF, 0xF9E14236, 0x7838162B, 0x59726C72, 0x81B66760, 0xBB2926C1, + 0x48A0CE0D, 0xA6C0496D, 0xAD43507B, 0x718D496A, 0x9DF057AF, 0x44B1BDE6, + 0x054356DC, 0xDE7CED35, 0xD51A138B, 0x62088CC9, 0x35830311, 0xC96EFCA2, + 0x686F86EC, 0x8E77CB68, 0x63E1D6B8, 0xC80F9778, 0x79C491FD, 0x1B4C67F2, + 0x72698D7D, 0x5E368C31, 0xF7D95E2E, 0xA1D3493F, 0xDCD9433E, 0x896F1552, + 0x4BC4CA7A, 0xA6D1BAF4, 0xA5A96DCC, 0x0BEF8B46, 0xA169FDA7, 0x74DF40B7, + 0x4E208804, 0x9A756607, 0x038E87C8, 0x20211E44, 0x8B7AD4BF, 0xC6403F35, + 0x1848E36D, 0x80BDB038, 0x1E62891C, 0x643D2107, 0xBF04D6F8, 0x21092C8C, + 0xF644F389, 0x0778404E, 0x7B78ADB8, 0xA2C52D53, 0x42157ABE, 0xA2253E2E, + 0x7BF3F4AE, 0x80F594F9, 0x953194E7, 0x77EB92ED, 0xB3816930, 0xDA8D9336, + 0xBF447469, 0xF26D9483, 0xEE6FAED5, 0x71371235, 0xDE425F73, 0xB4E59F43, + 0x7DBE2D4E, 0x2D37B185, 0x49DC9A63, 0x98C39D98, 0x1301C9A2, 0x389B1BBF, + 0x0C18588D, 0xA421C1BA, 0x7AA3865C, 0x71E08558, 0x3C5CFCAA, 0x7D239CA4, + 0x0297D9DD, 0xD7DC2830, 0x4B37802B, 0x7428AB54, 0xAEEE0347, 0x4B3FBB85, + 0x692F2F08, 0x134E578E, 0x36D9E0BF, 0xAE8B5FCF, 0xEDB93ECF, 0x2B27248E, + 0x170EB1EF, 0x7DC57FD6, 0x1E760F16, 0xB1136601, 0x864E1B9B, 0xD7EA7319, + 0x3AB871BD, 0xCFA4D76F, 0xE31BD782, 0x0DBEB469, 0xABB96061, 0x5370F85D, + 0xFFB07E37, 0xDA30D0FB, 0xEBC977B6, 0x0B98B40F, 0x3A4D0FE6, 0xDF4FC26B, + 0x159CF22A, 0xC298D6E2, 0x2B78EF6A, 0x61A94AC0, 0xAB561187, 0x14EEA0F0, + 0xDF0D4164, 0x19AF70EE }; + +/* +* MARS Encryption Round +*/ +inline void encrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, + u32bit EK1, u32bit EK2) + { + const u32bit X = A + EK1; + A = rotate_left(A, 13); + u32bit Y = A * EK2; + u32bit Z = SBOX[X % 512]; + + Y = rotate_left(Y, 5); + Z ^= Y; + C += rotate_left(X, Y % 32); + Y = rotate_left(Y, 5); + Z ^= Y; + D ^= Y; + B += rotate_left(Z, Y % 32); + } + +/* +* MARS Decryption Round +*/ +inline void decrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, + u32bit EK1, u32bit EK2) + { + u32bit Y = A * EK1; + A = rotate_right(A, 13); + const u32bit X = A + EK2; + u32bit Z = SBOX[X % 512]; + + Y = rotate_left(Y, 5); + Z ^= Y; + C -= rotate_left(X, Y % 32); + Y = rotate_left(Y, 5); + Z ^= Y; + D ^= Y; + B -= rotate_left(Z, Y % 32); + } + +/* +* MARS Forward Mixing Operation +*/ +void forward_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D) + { + for(size_t j = 0; j != 2; ++j) + { + B ^= SBOX[get_byte(3, A)]; B += SBOX[get_byte(2, A) + 256]; + C += SBOX[get_byte(1, A)]; D ^= SBOX[get_byte(0, A) + 256]; + A = rotate_right(A, 24) + D; + + C ^= SBOX[get_byte(3, B)]; C += SBOX[get_byte(2, B) + 256]; + D += SBOX[get_byte(1, B)]; A ^= SBOX[get_byte(0, B) + 256]; + B = rotate_right(B, 24) + C; + + D ^= SBOX[get_byte(3, C)]; D += SBOX[get_byte(2, C) + 256]; + A += SBOX[get_byte(1, C)]; B ^= SBOX[get_byte(0, C) + 256]; + C = rotate_right(C, 24); + + A ^= SBOX[get_byte(3, D)]; A += SBOX[get_byte(2, D) + 256]; + B += SBOX[get_byte(1, D)]; C ^= SBOX[get_byte(0, D) + 256]; + D = rotate_right(D, 24); + } + } + +/* +* MARS Reverse Mixing Operation +*/ +void reverse_mix(u32bit& A, u32bit& B, u32bit& C, u32bit& D) + { + for(size_t j = 0; j != 2; ++j) + { + B ^= SBOX[get_byte(3, A) + 256]; C -= SBOX[get_byte(0, A)]; + D -= SBOX[get_byte(1, A) + 256]; D ^= SBOX[get_byte(2, A)]; + A = rotate_left(A, 24); + + C ^= SBOX[get_byte(3, B) + 256]; D -= SBOX[get_byte(0, B)]; + A -= SBOX[get_byte(1, B) + 256]; A ^= SBOX[get_byte(2, B)]; + C -= (B = rotate_left(B, 24)); + + D ^= SBOX[get_byte(3, C) + 256]; A -= SBOX[get_byte(0, C)]; + B -= SBOX[get_byte(1, C) + 256]; B ^= SBOX[get_byte(2, C)]; + C = rotate_left(C, 24); + D -= A; + + A ^= SBOX[get_byte(3, D) + 256]; B -= SBOX[get_byte(0, D)]; + C -= SBOX[get_byte(1, D) + 256]; C ^= SBOX[get_byte(2, D)]; + D = rotate_left(D, 24); + } + } + +/* +* Generate a mask for runs of bits +*/ +u32bit gen_mask(u32bit input) + { + u32bit mask = 0; + + for(u32bit j = 2; j != 31; ++j) + { + const u32bit region = (input >> (j-1)) & 0x07; + + if(region == 0x00 || region == 0x07) + { + const u32bit low = (j < 9) ? 0 : (j - 9); + const u32bit high = (j < 23) ? j : 23; + + for(u32bit k = low; k != high; ++k) + { + const u32bit value = (input >> k) & 0x3FF; + + if(value == 0 || value == 0x3FF) + { + mask |= 1 << j; + break; + } + } + } + } + + return mask; + } + +} + +/* +* MARS Encryption +*/ +void MARS::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) + EK[0]; + u32bit B = load_le(in, 1) + EK[1]; + u32bit C = load_le(in, 2) + EK[2]; + u32bit D = load_le(in, 3) + EK[3]; + + forward_mix(A, B, C, D); + + encrypt_round(A, B, C, D, EK[ 4], EK[ 5]); + encrypt_round(B, C, D, A, EK[ 6], EK[ 7]); + encrypt_round(C, D, A, B, EK[ 8], EK[ 9]); + encrypt_round(D, A, B, C, EK[10], EK[11]); + encrypt_round(A, B, C, D, EK[12], EK[13]); + encrypt_round(B, C, D, A, EK[14], EK[15]); + encrypt_round(C, D, A, B, EK[16], EK[17]); + encrypt_round(D, A, B, C, EK[18], EK[19]); + + encrypt_round(A, D, C, B, EK[20], EK[21]); + encrypt_round(B, A, D, C, EK[22], EK[23]); + encrypt_round(C, B, A, D, EK[24], EK[25]); + encrypt_round(D, C, B, A, EK[26], EK[27]); + encrypt_round(A, D, C, B, EK[28], EK[29]); + encrypt_round(B, A, D, C, EK[30], EK[31]); + encrypt_round(C, B, A, D, EK[32], EK[33]); + encrypt_round(D, C, B, A, EK[34], EK[35]); + + reverse_mix(A, B, C, D); + + A -= EK[36]; B -= EK[37]; C -= EK[38]; D -= EK[39]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MARS Decryption +*/ +void MARS::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 3) + EK[39]; + u32bit B = load_le(in, 2) + EK[38]; + u32bit C = load_le(in, 1) + EK[37]; + u32bit D = load_le(in, 0) + EK[36]; + + forward_mix(A, B, C, D); + + decrypt_round(A, B, C, D, EK[35], EK[34]); + decrypt_round(B, C, D, A, EK[33], EK[32]); + decrypt_round(C, D, A, B, EK[31], EK[30]); + decrypt_round(D, A, B, C, EK[29], EK[28]); + decrypt_round(A, B, C, D, EK[27], EK[26]); + decrypt_round(B, C, D, A, EK[25], EK[24]); + decrypt_round(C, D, A, B, EK[23], EK[22]); + decrypt_round(D, A, B, C, EK[21], EK[20]); + + decrypt_round(A, D, C, B, EK[19], EK[18]); + decrypt_round(B, A, D, C, EK[17], EK[16]); + decrypt_round(C, B, A, D, EK[15], EK[14]); + decrypt_round(D, C, B, A, EK[13], EK[12]); + decrypt_round(A, D, C, B, EK[11], EK[10]); + decrypt_round(B, A, D, C, EK[ 9], EK[ 8]); + decrypt_round(C, B, A, D, EK[ 7], EK[ 6]); + decrypt_round(D, C, B, A, EK[ 5], EK[ 4]); + + reverse_mix(A, B, C, D); + + A -= EK[3]; B -= EK[2]; C -= EK[1]; D -= EK[0]; + + store_le(out, D, C, B, A); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MARS Key Schedule +*/ +void MARS::key_schedule(const byte key[], size_t length) + { + SecureVector T(15); + for(size_t i = 0; i != length / 4; ++i) + T[i] = load_le(key, i); + + T[length / 4] = static_cast(length) / 4; + + for(u32bit i = 0; i != 4; ++i) + { + T[ 0] ^= rotate_left(T[ 8] ^ T[13], 3) ^ (i ); + T[ 1] ^= rotate_left(T[ 9] ^ T[14], 3) ^ (i + 4); + T[ 2] ^= rotate_left(T[10] ^ T[ 0], 3) ^ (i + 8); + T[ 3] ^= rotate_left(T[11] ^ T[ 1], 3) ^ (i + 12); + T[ 4] ^= rotate_left(T[12] ^ T[ 2], 3) ^ (i + 16); + T[ 5] ^= rotate_left(T[13] ^ T[ 3], 3) ^ (i + 20); + T[ 6] ^= rotate_left(T[14] ^ T[ 4], 3) ^ (i + 24); + T[ 7] ^= rotate_left(T[ 0] ^ T[ 5], 3) ^ (i + 28); + T[ 8] ^= rotate_left(T[ 1] ^ T[ 6], 3) ^ (i + 32); + T[ 9] ^= rotate_left(T[ 2] ^ T[ 7], 3) ^ (i + 36); + T[10] ^= rotate_left(T[ 3] ^ T[ 8], 3) ^ (i + 40); + T[11] ^= rotate_left(T[ 4] ^ T[ 9], 3) ^ (i + 44); + T[12] ^= rotate_left(T[ 5] ^ T[10], 3) ^ (i + 48); + T[13] ^= rotate_left(T[ 6] ^ T[11], 3) ^ (i + 52); + T[14] ^= rotate_left(T[ 7] ^ T[12], 3) ^ (i + 56); + + for(size_t j = 0; j != 4; ++j) + { + T[ 0] = rotate_left(T[ 0] + SBOX[T[14] % 512], 9); + T[ 1] = rotate_left(T[ 1] + SBOX[T[ 0] % 512], 9); + T[ 2] = rotate_left(T[ 2] + SBOX[T[ 1] % 512], 9); + T[ 3] = rotate_left(T[ 3] + SBOX[T[ 2] % 512], 9); + T[ 4] = rotate_left(T[ 4] + SBOX[T[ 3] % 512], 9); + T[ 5] = rotate_left(T[ 5] + SBOX[T[ 4] % 512], 9); + T[ 6] = rotate_left(T[ 6] + SBOX[T[ 5] % 512], 9); + T[ 7] = rotate_left(T[ 7] + SBOX[T[ 6] % 512], 9); + T[ 8] = rotate_left(T[ 8] + SBOX[T[ 7] % 512], 9); + T[ 9] = rotate_left(T[ 9] + SBOX[T[ 8] % 512], 9); + T[10] = rotate_left(T[10] + SBOX[T[ 9] % 512], 9); + T[11] = rotate_left(T[11] + SBOX[T[10] % 512], 9); + T[12] = rotate_left(T[12] + SBOX[T[11] % 512], 9); + T[13] = rotate_left(T[13] + SBOX[T[12] % 512], 9); + T[14] = rotate_left(T[14] + SBOX[T[13] % 512], 9); + } + + EK[10*i + 0] = T[ 0]; + EK[10*i + 1] = T[ 4]; + EK[10*i + 2] = T[ 8]; + EK[10*i + 3] = T[12]; + EK[10*i + 4] = T[ 1]; + EK[10*i + 5] = T[ 5]; + EK[10*i + 6] = T[ 9]; + EK[10*i + 7] = T[13]; + EK[10*i + 8] = T[ 2]; + EK[10*i + 9] = T[ 6]; + } + + for(size_t i = 5; i != 37; i += 2) + { + const u32bit key3 = EK[i] & 3; + EK[i] |= 3; + EK[i] ^= rotate_left(SBOX[265 + key3], EK[i-1] % 32) & gen_mask(EK[i]); + } + } + +} +/* +* MISTY1 +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +static const byte MISTY1_SBOX_S7[128] = { + 0x1B, 0x32, 0x33, 0x5A, 0x3B, 0x10, 0x17, 0x54, 0x5B, 0x1A, 0x72, 0x73, + 0x6B, 0x2C, 0x66, 0x49, 0x1F, 0x24, 0x13, 0x6C, 0x37, 0x2E, 0x3F, 0x4A, + 0x5D, 0x0F, 0x40, 0x56, 0x25, 0x51, 0x1C, 0x04, 0x0B, 0x46, 0x20, 0x0D, + 0x7B, 0x35, 0x44, 0x42, 0x2B, 0x1E, 0x41, 0x14, 0x4B, 0x79, 0x15, 0x6F, + 0x0E, 0x55, 0x09, 0x36, 0x74, 0x0C, 0x67, 0x53, 0x28, 0x0A, 0x7E, 0x38, + 0x02, 0x07, 0x60, 0x29, 0x19, 0x12, 0x65, 0x2F, 0x30, 0x39, 0x08, 0x68, + 0x5F, 0x78, 0x2A, 0x4C, 0x64, 0x45, 0x75, 0x3D, 0x59, 0x48, 0x03, 0x57, + 0x7C, 0x4F, 0x62, 0x3C, 0x1D, 0x21, 0x5E, 0x27, 0x6A, 0x70, 0x4D, 0x3A, + 0x01, 0x6D, 0x6E, 0x63, 0x18, 0x77, 0x23, 0x05, 0x26, 0x76, 0x00, 0x31, + 0x2D, 0x7A, 0x7F, 0x61, 0x50, 0x22, 0x11, 0x06, 0x47, 0x16, 0x52, 0x4E, + 0x71, 0x3E, 0x69, 0x43, 0x34, 0x5C, 0x58, 0x7D }; + +static const u16bit MISTY1_SBOX_S9[512] = { + 0x01C3, 0x00CB, 0x0153, 0x019F, 0x01E3, 0x00E9, 0x00FB, 0x0035, 0x0181, + 0x00B9, 0x0117, 0x01EB, 0x0133, 0x0009, 0x002D, 0x00D3, 0x00C7, 0x014A, + 0x0037, 0x007E, 0x00EB, 0x0164, 0x0193, 0x01D8, 0x00A3, 0x011E, 0x0055, + 0x002C, 0x001D, 0x01A2, 0x0163, 0x0118, 0x014B, 0x0152, 0x01D2, 0x000F, + 0x002B, 0x0030, 0x013A, 0x00E5, 0x0111, 0x0138, 0x018E, 0x0063, 0x00E3, + 0x00C8, 0x01F4, 0x001B, 0x0001, 0x009D, 0x00F8, 0x01A0, 0x016D, 0x01F3, + 0x001C, 0x0146, 0x007D, 0x00D1, 0x0082, 0x01EA, 0x0183, 0x012D, 0x00F4, + 0x019E, 0x01D3, 0x00DD, 0x01E2, 0x0128, 0x01E0, 0x00EC, 0x0059, 0x0091, + 0x0011, 0x012F, 0x0026, 0x00DC, 0x00B0, 0x018C, 0x010F, 0x01F7, 0x00E7, + 0x016C, 0x00B6, 0x00F9, 0x00D8, 0x0151, 0x0101, 0x014C, 0x0103, 0x00B8, + 0x0154, 0x012B, 0x01AE, 0x0017, 0x0071, 0x000C, 0x0047, 0x0058, 0x007F, + 0x01A4, 0x0134, 0x0129, 0x0084, 0x015D, 0x019D, 0x01B2, 0x01A3, 0x0048, + 0x007C, 0x0051, 0x01CA, 0x0023, 0x013D, 0x01A7, 0x0165, 0x003B, 0x0042, + 0x00DA, 0x0192, 0x00CE, 0x00C1, 0x006B, 0x009F, 0x01F1, 0x012C, 0x0184, + 0x00FA, 0x0196, 0x01E1, 0x0169, 0x017D, 0x0031, 0x0180, 0x010A, 0x0094, + 0x01DA, 0x0186, 0x013E, 0x011C, 0x0060, 0x0175, 0x01CF, 0x0067, 0x0119, + 0x0065, 0x0068, 0x0099, 0x0150, 0x0008, 0x0007, 0x017C, 0x00B7, 0x0024, + 0x0019, 0x00DE, 0x0127, 0x00DB, 0x00E4, 0x01A9, 0x0052, 0x0109, 0x0090, + 0x019C, 0x01C1, 0x0028, 0x01B3, 0x0135, 0x016A, 0x0176, 0x00DF, 0x01E5, + 0x0188, 0x00C5, 0x016E, 0x01DE, 0x01B1, 0x00C3, 0x01DF, 0x0036, 0x00EE, + 0x01EE, 0x00F0, 0x0093, 0x0049, 0x009A, 0x01B6, 0x0069, 0x0081, 0x0125, + 0x000B, 0x005E, 0x00B4, 0x0149, 0x01C7, 0x0174, 0x003E, 0x013B, 0x01B7, + 0x008E, 0x01C6, 0x00AE, 0x0010, 0x0095, 0x01EF, 0x004E, 0x00F2, 0x01FD, + 0x0085, 0x00FD, 0x00F6, 0x00A0, 0x016F, 0x0083, 0x008A, 0x0156, 0x009B, + 0x013C, 0x0107, 0x0167, 0x0098, 0x01D0, 0x01E9, 0x0003, 0x01FE, 0x00BD, + 0x0122, 0x0089, 0x00D2, 0x018F, 0x0012, 0x0033, 0x006A, 0x0142, 0x00ED, + 0x0170, 0x011B, 0x00E2, 0x014F, 0x0158, 0x0131, 0x0147, 0x005D, 0x0113, + 0x01CD, 0x0079, 0x0161, 0x01A5, 0x0179, 0x009E, 0x01B4, 0x00CC, 0x0022, + 0x0132, 0x001A, 0x00E8, 0x0004, 0x0187, 0x01ED, 0x0197, 0x0039, 0x01BF, + 0x01D7, 0x0027, 0x018B, 0x00C6, 0x009C, 0x00D0, 0x014E, 0x006C, 0x0034, + 0x01F2, 0x006E, 0x00CA, 0x0025, 0x00BA, 0x0191, 0x00FE, 0x0013, 0x0106, + 0x002F, 0x01AD, 0x0172, 0x01DB, 0x00C0, 0x010B, 0x01D6, 0x00F5, 0x01EC, + 0x010D, 0x0076, 0x0114, 0x01AB, 0x0075, 0x010C, 0x01E4, 0x0159, 0x0054, + 0x011F, 0x004B, 0x00C4, 0x01BE, 0x00F7, 0x0029, 0x00A4, 0x000E, 0x01F0, + 0x0077, 0x004D, 0x017A, 0x0086, 0x008B, 0x00B3, 0x0171, 0x00BF, 0x010E, + 0x0104, 0x0097, 0x015B, 0x0160, 0x0168, 0x00D7, 0x00BB, 0x0066, 0x01CE, + 0x00FC, 0x0092, 0x01C5, 0x006F, 0x0016, 0x004A, 0x00A1, 0x0139, 0x00AF, + 0x00F1, 0x0190, 0x000A, 0x01AA, 0x0143, 0x017B, 0x0056, 0x018D, 0x0166, + 0x00D4, 0x01FB, 0x014D, 0x0194, 0x019A, 0x0087, 0x01F8, 0x0123, 0x00A7, + 0x01B8, 0x0141, 0x003C, 0x01F9, 0x0140, 0x002A, 0x0155, 0x011A, 0x01A1, + 0x0198, 0x00D5, 0x0126, 0x01AF, 0x0061, 0x012E, 0x0157, 0x01DC, 0x0072, + 0x018A, 0x00AA, 0x0096, 0x0115, 0x00EF, 0x0045, 0x007B, 0x008D, 0x0145, + 0x0053, 0x005F, 0x0178, 0x00B2, 0x002E, 0x0020, 0x01D5, 0x003F, 0x01C9, + 0x01E7, 0x01AC, 0x0044, 0x0038, 0x0014, 0x00B1, 0x016B, 0x00AB, 0x00B5, + 0x005A, 0x0182, 0x01C8, 0x01D4, 0x0018, 0x0177, 0x0064, 0x00CF, 0x006D, + 0x0100, 0x0199, 0x0130, 0x015A, 0x0005, 0x0120, 0x01BB, 0x01BD, 0x00E0, + 0x004F, 0x00D6, 0x013F, 0x01C4, 0x012A, 0x0015, 0x0006, 0x00FF, 0x019B, + 0x00A6, 0x0043, 0x0088, 0x0050, 0x015F, 0x01E8, 0x0121, 0x0073, 0x017E, + 0x00BC, 0x00C2, 0x00C9, 0x0173, 0x0189, 0x01F5, 0x0074, 0x01CC, 0x01E6, + 0x01A8, 0x0195, 0x001F, 0x0041, 0x000D, 0x01BA, 0x0032, 0x003D, 0x01D1, + 0x0080, 0x00A8, 0x0057, 0x01B9, 0x0162, 0x0148, 0x00D9, 0x0105, 0x0062, + 0x007A, 0x0021, 0x01FF, 0x0112, 0x0108, 0x01C0, 0x00A9, 0x011D, 0x01B0, + 0x01A6, 0x00CD, 0x00F3, 0x005C, 0x0102, 0x005B, 0x01D9, 0x0144, 0x01F6, + 0x00AD, 0x00A5, 0x003A, 0x01CB, 0x0136, 0x017F, 0x0046, 0x00E1, 0x001E, + 0x01DD, 0x00E6, 0x0137, 0x01FA, 0x0185, 0x008C, 0x008F, 0x0040, 0x01B5, + 0x00BE, 0x0078, 0x0000, 0x00AC, 0x0110, 0x015E, 0x0124, 0x0002, 0x01BC, + 0x00A2, 0x00EA, 0x0070, 0x01FC, 0x0116, 0x015C, 0x004C, 0x01C2 }; + +/* +* MISTY1 FI Function +*/ +u16bit FI(u16bit input, u16bit key7, u16bit key9) + { + u16bit D9 = input >> 7, D7 = input & 0x7F; + D9 = MISTY1_SBOX_S9[D9] ^ D7; + D7 = (MISTY1_SBOX_S7[D7] ^ key7 ^ D9) & 0x7F; + D9 = MISTY1_SBOX_S9[D9 ^ key9] ^ D7; + return static_cast((D7 << 9) | D9); + } + +} + +/* +* MISTY1 Encryption +*/ +void MISTY1::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 0); + u16bit B1 = load_be(in, 1); + u16bit B2 = load_be(in, 2); + u16bit B3 = load_be(in, 3); + + for(size_t j = 0; j != 12; j += 3) + { + const u16bit* RK = &EK[8 * j]; + + B1 ^= B0 & RK[0]; + B0 ^= B1 | RK[1]; + B3 ^= B2 & RK[2]; + B2 ^= B3 | RK[3]; + + u32bit T0, T1; + + T0 = FI(B0 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B1; + T1 = FI(B1 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B2 ^= T1 ^ RK[13]; + B3 ^= T0; + + T0 = FI(B2 ^ RK[14], RK[15], RK[16]) ^ B3; + T1 = FI(B3 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B0 ^= T1 ^ RK[23]; + B1 ^= T0; + } + + B1 ^= B0 & EK[96]; + B0 ^= B1 | EK[97]; + B3 ^= B2 & EK[98]; + B2 ^= B3 | EK[99]; + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Decryption +*/ +void MISTY1::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit B0 = load_be(in, 2); + u16bit B1 = load_be(in, 3); + u16bit B2 = load_be(in, 0); + u16bit B3 = load_be(in, 1); + + for(size_t j = 0; j != 12; j += 3) + { + const u16bit* RK = &DK[8 * j]; + + B2 ^= B3 | RK[0]; + B3 ^= B2 & RK[1]; + B0 ^= B1 | RK[2]; + B1 ^= B0 & RK[3]; + + u32bit T0, T1; + + T0 = FI(B2 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B3; + T1 = FI(B3 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B0 ^= T1 ^ RK[13]; + B1 ^= T0; + + T0 = FI(B0 ^ RK[14], RK[15], RK[16]) ^ B1; + T1 = FI(B1 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B2 ^= T1 ^ RK[23]; + B3 ^= T0; + } + + B2 ^= B3 | DK[96]; + B3 ^= B2 & DK[97]; + B0 ^= B1 | DK[98]; + B1 ^= B0 & DK[99]; + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Key Schedule +*/ +void MISTY1::key_schedule(const byte key[], size_t length) + { + SecureVector KS(32); + for(size_t i = 0; i != length / 2; ++i) + KS[i] = load_be(key, i); + + for(size_t i = 0; i != 8; ++i) + { + KS[i+ 8] = FI(KS[i], KS[(i+1) % 8] >> 9, KS[(i+1) % 8] & 0x1FF); + KS[i+16] = KS[i+8] >> 9; + KS[i+24] = KS[i+8] & 0x1FF; + } + + /* + * Precomputed indexes for the orderings of the subkeys (MISTY1 reuses + * values) + */ + static const byte EK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, + 0x1B, 0x04, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05, + 0x01, 0x0F, 0x0B, 0x05, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, + 0x1D, 0x06, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07, + 0x02, 0x08, 0x0C, 0x06, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, + 0x1F, 0x00, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01, + 0x03, 0x09, 0x0D, 0x07, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, + 0x19, 0x02, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03, + 0x04, 0x0A, 0x0E, 0x00 }; + + static const byte DK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, + 0x1A, 0x03, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02, + 0x07, 0x0D, 0x09, 0x03, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, + 0x18, 0x01, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00, + 0x06, 0x0C, 0x08, 0x02, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, + 0x1E, 0x07, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06, + 0x05, 0x0B, 0x0F, 0x01, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, + 0x1C, 0x05, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04, + 0x04, 0x0A, 0x0E, 0x00 }; + + for(size_t i = 0; i != 100; ++i) + { + EK[i] = KS[EK_ORDER[i]]; + DK[i] = KS[DK_ORDER[i]]; + } + } + +/* +* MISTY1 Constructor +*/ +MISTY1::MISTY1(size_t rounds) : EK(100), DK(100) + { + if(rounds != 8) + throw Invalid_Argument("MISTY1: Invalid number of rounds: " + + to_string(rounds)); + } + +} +/* +* Noekeon +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Noekeon's Theta Operation +*/ +inline void theta(u32bit& A0, u32bit& A1, + u32bit& A2, u32bit& A3, + const u32bit EK[4]) + { + u32bit T = A0 ^ A2; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A1 ^= T; + A3 ^= T; + + A0 ^= EK[0]; + A1 ^= EK[1]; + A2 ^= EK[2]; + A3 ^= EK[3]; + + T = A1 ^ A3; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A0 ^= T; + A2 ^= T; + } + +/* +* Theta With Null Key +*/ +inline void theta(u32bit& A0, u32bit& A1, + u32bit& A2, u32bit& A3) + { + u32bit T = A0 ^ A2; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A1 ^= T; + A3 ^= T; + + T = A1 ^ A3; + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); + A0 ^= T; + A2 ^= T; + } + +/* +* Noekeon's Gamma S-Box Layer +*/ +inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3) + { + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + + u32bit T = A3; + A3 = A0; + A0 = T; + + A2 ^= A0 ^ A1 ^ A3; + + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + } + +} + +/* +* Noekeon Round Constants +*/ +const byte Noekeon::RC[] = { + 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, + 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, + 0xD4 }; + +/* +* Noekeon Encryption +*/ +void Noekeon::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A0 = load_be(in, 0); + u32bit A1 = load_be(in, 1); + u32bit A2 = load_be(in, 2); + u32bit A3 = load_be(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + A0 ^= RC[j]; + theta(A0, A1, A2, A3, &EK[0]); + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + A0 ^= RC[16]; + theta(A0, A1, A2, A3, &EK[0]); + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Encryption +*/ +void Noekeon::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A0 = load_be(in, 0); + u32bit A1 = load_be(in, 1); + u32bit A2 = load_be(in, 2); + u32bit A3 = load_be(in, 3); + + for(size_t j = 16; j != 0; --j) + { + theta(A0, A1, A2, A3, &DK[0]); + A0 ^= RC[j]; + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + theta(A0, A1, A2, A3, &DK[0]); + A0 ^= RC[0]; + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Key Schedule +*/ +void Noekeon::key_schedule(const byte key[], size_t) + { + u32bit A0 = load_be(key, 0); + u32bit A1 = load_be(key, 1); + u32bit A2 = load_be(key, 2); + u32bit A3 = load_be(key, 3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= RC[i]; + theta(A0, A1, A2, A3); + + A1 = rotate_left(A1, 1); + A2 = rotate_left(A2, 5); + A3 = rotate_left(A3, 2); + + gamma(A0, A1, A2, A3); + + A1 = rotate_right(A1, 1); + A2 = rotate_right(A2, 5); + A3 = rotate_right(A3, 2); + } + + A0 ^= RC[16]; + + DK[0] = A0; + DK[1] = A1; + DK[2] = A2; + DK[3] = A3; + + theta(A0, A1, A2, A3); + + EK[0] = A0; + EK[1] = A1; + EK[2] = A2; + EK[3] = A3; + } + +/* +* Clear memory of sensitive data +*/ +void Noekeon::clear() + { + zeroise(EK); + zeroise(DK); + } + +} +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Noekeon's Theta Operation +*/ +#define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ + do { \ + SIMD_32 T = A0 ^ A2; \ + SIMD_32 T_l8 = T; \ + SIMD_32 T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ + A1 ^= T; \ + A3 ^= T; \ + \ + A0 ^= K0; \ + A1 ^= K1; \ + A2 ^= K2; \ + A3 ^= K3; \ + \ + T = A1 ^ A3; \ + T_l8 = T; \ + T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ + A0 ^= T; \ + A2 ^= T; \ + } while(0) + +/* +* Noekeon's Gamma S-Box Layer +*/ +#define NOK_SIMD_GAMMA(A0, A1, A2, A3) \ + do \ + { \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + \ + SIMD_32 T = A3; \ + A3 = A0; \ + A0 = T; \ + \ + A2 ^= A0 ^ A1 ^ A3; \ + \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + } while(0) + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const SecureVector& EK = this->get_EK(); + + SIMD_32 K0 = SIMD_32(EK[0]); + SIMD_32 K1 = SIMD_32(EK[1]); + SIMD_32 K2 = SIMD_32(EK[2]); + SIMD_32 K3 = SIMD_32(EK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= SIMD_32(RC[i]); + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + A0 ^= SIMD_32(RC[16]); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + if(blocks) + Noekeon::encrypt_n(in, out, blocks); + } + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const SecureVector& DK = this->get_DK(); + + SIMD_32 K0 = SIMD_32(DK[0]); + SIMD_32 K1 = SIMD_32(DK[1]); + SIMD_32 K2 = SIMD_32(DK[2]); + SIMD_32 K3 = SIMD_32(DK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A0 ^= SIMD_32(RC[16-i]); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + A0 ^= SIMD_32(RC[0]); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + if(blocks) + Noekeon::decrypt_n(in, out, blocks); + } + +} +/* +* RC2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* RC2 Encryption +*/ +void RC2::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit R0 = load_le(in, 0); + u16bit R1 = load_le(in, 1); + u16bit R2 = load_le(in, 2); + u16bit R3 = load_le(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + R0 += (R1 & ~R3) + (R2 & R3) + K[4*j]; + R0 = rotate_left(R0, 1); + + R1 += (R2 & ~R0) + (R3 & R0) + K[4*j + 1]; + R1 = rotate_left(R1, 2); + + R2 += (R3 & ~R1) + (R0 & R1) + K[4*j + 2]; + R2 = rotate_left(R2, 3); + + R3 += (R0 & ~R2) + (R1 & R2) + K[4*j + 3]; + R3 = rotate_left(R3, 5); + + if(j == 4 || j == 10) + { + R0 += K[R3 % 64]; + R1 += K[R0 % 64]; + R2 += K[R1 % 64]; + R3 += K[R2 % 64]; + } + } + + store_le(out, R0, R1, R2, R3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC2 Decryption +*/ +void RC2::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u16bit R0 = load_le(in, 0); + u16bit R1 = load_le(in, 1); + u16bit R2 = load_le(in, 2); + u16bit R3 = load_le(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + R3 = rotate_right(R3, 5); + R3 -= (R0 & ~R2) + (R1 & R2) + K[63 - (4*j + 0)]; + + R2 = rotate_right(R2, 3); + R2 -= (R3 & ~R1) + (R0 & R1) + K[63 - (4*j + 1)]; + + R1 = rotate_right(R1, 2); + R1 -= (R2 & ~R0) + (R3 & R0) + K[63 - (4*j + 2)]; + + R0 = rotate_right(R0, 1); + R0 -= (R1 & ~R3) + (R2 & R3) + K[63 - (4*j + 3)]; + + if(j == 4 || j == 10) + { + R3 -= K[R2 % 64]; + R2 -= K[R1 % 64]; + R1 -= K[R0 % 64]; + R0 -= K[R3 % 64]; + } + } + + store_le(out, R0, R1, R2, R3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC2 Key Schedule +*/ +void RC2::key_schedule(const byte key[], size_t length) + { + static const byte TABLE[256] = { + 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79, + 0x4A, 0xA0, 0xD8, 0x9D, 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, + 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 0x17, 0x9A, 0x59, 0xF5, + 0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, + 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22, + 0x5C, 0x6B, 0x4E, 0x82, 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, + 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 0x12, 0x75, 0xCA, 0x1F, + 0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, + 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B, + 0xBC, 0x94, 0x43, 0x03, 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, + 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 0x08, 0xE8, 0xEA, 0xDE, + 0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, + 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E, + 0x04, 0x18, 0xA4, 0xEC, 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, + 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 0x99, 0x7C, 0x3A, 0x85, + 0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, + 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10, + 0x67, 0x6C, 0xBA, 0xC9, 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, + 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 0x0D, 0x38, 0x34, 0x1B, + 0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, + 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68, + 0xFE, 0x7F, 0xC1, 0xAD }; + + SecureVector L(128); + L.copy(key, length); + + for(size_t i = length; i != 128; ++i) + L[i] = TABLE[(L[i-1] + L[i-length]) % 256]; + + L[128-length] = TABLE[L[128-length]]; + + for(s32bit i = 127-length; i >= 0; --i) + L[i] = TABLE[L[i+1] ^ L[i+length]]; + + load_le(&K[0], &L[0], 64); + } + +/* +* Return the code of the effective key bits +*/ +byte RC2::EKB_code(size_t ekb) + { + const byte EKB[256] = { + 0xBD, 0x56, 0xEA, 0xF2, 0xA2, 0xF1, 0xAC, 0x2A, 0xB0, 0x93, 0xD1, 0x9C, + 0x1B, 0x33, 0xFD, 0xD0, 0x30, 0x04, 0xB6, 0xDC, 0x7D, 0xDF, 0x32, 0x4B, + 0xF7, 0xCB, 0x45, 0x9B, 0x31, 0xBB, 0x21, 0x5A, 0x41, 0x9F, 0xE1, 0xD9, + 0x4A, 0x4D, 0x9E, 0xDA, 0xA0, 0x68, 0x2C, 0xC3, 0x27, 0x5F, 0x80, 0x36, + 0x3E, 0xEE, 0xFB, 0x95, 0x1A, 0xFE, 0xCE, 0xA8, 0x34, 0xA9, 0x13, 0xF0, + 0xA6, 0x3F, 0xD8, 0x0C, 0x78, 0x24, 0xAF, 0x23, 0x52, 0xC1, 0x67, 0x17, + 0xF5, 0x66, 0x90, 0xE7, 0xE8, 0x07, 0xB8, 0x60, 0x48, 0xE6, 0x1E, 0x53, + 0xF3, 0x92, 0xA4, 0x72, 0x8C, 0x08, 0x15, 0x6E, 0x86, 0x00, 0x84, 0xFA, + 0xF4, 0x7F, 0x8A, 0x42, 0x19, 0xF6, 0xDB, 0xCD, 0x14, 0x8D, 0x50, 0x12, + 0xBA, 0x3C, 0x06, 0x4E, 0xEC, 0xB3, 0x35, 0x11, 0xA1, 0x88, 0x8E, 0x2B, + 0x94, 0x99, 0xB7, 0x71, 0x74, 0xD3, 0xE4, 0xBF, 0x3A, 0xDE, 0x96, 0x0E, + 0xBC, 0x0A, 0xED, 0x77, 0xFC, 0x37, 0x6B, 0x03, 0x79, 0x89, 0x62, 0xC6, + 0xD7, 0xC0, 0xD2, 0x7C, 0x6A, 0x8B, 0x22, 0xA3, 0x5B, 0x05, 0x5D, 0x02, + 0x75, 0xD5, 0x61, 0xE3, 0x18, 0x8F, 0x55, 0x51, 0xAD, 0x1F, 0x0B, 0x5E, + 0x85, 0xE5, 0xC2, 0x57, 0x63, 0xCA, 0x3D, 0x6C, 0xB4, 0xC5, 0xCC, 0x70, + 0xB2, 0x91, 0x59, 0x0D, 0x47, 0x20, 0xC8, 0x4F, 0x58, 0xE0, 0x01, 0xE2, + 0x16, 0x38, 0xC4, 0x6F, 0x3B, 0x0F, 0x65, 0x46, 0xBE, 0x7E, 0x2D, 0x7B, + 0x82, 0xF9, 0x40, 0xB5, 0x1D, 0x73, 0xF8, 0xEB, 0x26, 0xC7, 0x87, 0x97, + 0x25, 0x54, 0xB1, 0x28, 0xAA, 0x98, 0x9D, 0xA5, 0x64, 0x6D, 0x7A, 0xD4, + 0x10, 0x81, 0x44, 0xEF, 0x49, 0xD6, 0xAE, 0x2E, 0xDD, 0x76, 0x5C, 0x2F, + 0xA7, 0x1C, 0xC9, 0x09, 0x69, 0x9A, 0x83, 0xCF, 0x29, 0x39, 0xB9, 0xE9, + 0x4C, 0xFF, 0x43, 0xAB }; + + if(ekb < 256) + return EKB[ekb]; + else + throw Encoding_Error("RC2::EKB_code: EKB is too large"); + } + +} +/* +* RC5 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* RC5 Encryption +*/ +void RC5::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t rounds = (S.size() - 2) / 2; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + + A += S[0]; B += S[1]; + for(size_t j = 0; j != rounds; j += 4) + { + A = rotate_left(A ^ B, B % 32) + S[2*j+2]; + B = rotate_left(B ^ A, A % 32) + S[2*j+3]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+4]; + B = rotate_left(B ^ A, A % 32) + S[2*j+5]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+6]; + B = rotate_left(B ^ A, A % 32) + S[2*j+7]; + + A = rotate_left(A ^ B, B % 32) + S[2*j+8]; + B = rotate_left(B ^ A, A % 32) + S[2*j+9]; + } + + store_le(out, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC5 Decryption +*/ +void RC5::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t rounds = (S.size() - 2) / 2; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + + for(size_t j = rounds; j != 0; j -= 4) + { + B = rotate_right(B - S[2*j+1], A % 32) ^ A; + A = rotate_right(A - S[2*j ], B % 32) ^ B; + + B = rotate_right(B - S[2*j-1], A % 32) ^ A; + A = rotate_right(A - S[2*j-2], B % 32) ^ B; + + B = rotate_right(B - S[2*j-3], A % 32) ^ A; + A = rotate_right(A - S[2*j-4], B % 32) ^ B; + + B = rotate_right(B - S[2*j-5], A % 32) ^ A; + A = rotate_right(A - S[2*j-6], B % 32) ^ B; + } + B -= S[1]; A -= S[0]; + + store_le(out, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC5 Key Schedule +*/ +void RC5::key_schedule(const byte key[], size_t length) + { + const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1); + const size_t MIX_ROUNDS = 3 * std::max(WORD_KEYLENGTH, S.size()); + + S[0] = 0xB7E15163; + for(size_t i = 1; i != S.size(); ++i) + S[i] = S[i-1] + 0x9E3779B9; + + SecureVector K(8); + + for(s32bit i = length-1; i >= 0; --i) + K[i/4] = (K[i/4] << 8) + key[i]; + + u32bit A = 0, B = 0; + + for(size_t i = 0; i != MIX_ROUNDS; ++i) + { + A = rotate_left(S[i % S.size()] + A + B, 3); + B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32); + S[i % S.size()] = A; + K[i % WORD_KEYLENGTH] = B; + } + } + +/* +* Return the name of this type +*/ +std::string RC5::name() const + { + return "RC5(" + to_string(get_rounds()) + ")"; + } + +/* +* RC5 Constructor +*/ +RC5::RC5(size_t rounds) + { + if(rounds < 8 || rounds > 32 || (rounds % 4 != 0)) + throw Invalid_Argument("RC5: Invalid number of rounds " + + to_string(rounds)); + + S.resize(2*rounds + 2); + } + +} +/* +* RC6 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* RC6 Encryption +*/ +void RC6::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + u32bit C = load_le(in, 2); + u32bit D = load_le(in, 3); + + B += S[0]; D += S[1]; + + for(size_t j = 0; j != 20; j += 4) + { + u32bit T1, T2; + + T1 = rotate_left(B*(2*B+1), 5); + T2 = rotate_left(D*(2*D+1), 5); + A = rotate_left(A ^ T1, T2 % 32) + S[2*j+2]; + C = rotate_left(C ^ T2, T1 % 32) + S[2*j+3]; + + T1 = rotate_left(C*(2*C+1), 5); + T2 = rotate_left(A*(2*A+1), 5); + B = rotate_left(B ^ T1, T2 % 32) + S[2*j+4]; + D = rotate_left(D ^ T2, T1 % 32) + S[2*j+5]; + + T1 = rotate_left(D*(2*D+1), 5); + T2 = rotate_left(B*(2*B+1), 5); + C = rotate_left(C ^ T1, T2 % 32) + S[2*j+6]; + A = rotate_left(A ^ T2, T1 % 32) + S[2*j+7]; + + T1 = rotate_left(A*(2*A+1), 5); + T2 = rotate_left(C*(2*C+1), 5); + D = rotate_left(D ^ T1, T2 % 32) + S[2*j+8]; + B = rotate_left(B ^ T2, T1 % 32) + S[2*j+9]; + } + + A += S[42]; C += S[43]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC6 Decryption +*/ +void RC6::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0); + u32bit B = load_le(in, 1); + u32bit C = load_le(in, 2); + u32bit D = load_le(in, 3); + + C -= S[43]; A -= S[42]; + + for(size_t j = 0; j != 20; j += 4) + { + u32bit T1, T2; + + T1 = rotate_left(A*(2*A+1), 5); + T2 = rotate_left(C*(2*C+1), 5); + B = rotate_right(B - S[41 - 2*j], T1 % 32) ^ T2; + D = rotate_right(D - S[40 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(D*(2*D+1), 5); + T2 = rotate_left(B*(2*B+1), 5); + A = rotate_right(A - S[39 - 2*j], T1 % 32) ^ T2; + C = rotate_right(C - S[38 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(C*(2*C+1), 5); + T2 = rotate_left(A*(2*A+1), 5); + D = rotate_right(D - S[37 - 2*j], T1 % 32) ^ T2; + B = rotate_right(B - S[36 - 2*j], T2 % 32) ^ T1; + + T1 = rotate_left(B*(2*B+1), 5); + T2 = rotate_left(D*(2*D+1), 5); + C = rotate_right(C - S[35 - 2*j], T1 % 32) ^ T2; + A = rotate_right(A - S[34 - 2*j], T2 % 32) ^ T1; + } + + D -= S[1]; B -= S[0]; + + store_le(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* RC6 Key Schedule +*/ +void RC6::key_schedule(const byte key[], size_t length) + { + const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1); + const size_t MIX_ROUNDS = 3 * std::max(WORD_KEYLENGTH, S.size()); + + S[0] = 0xB7E15163; + for(size_t i = 1; i != S.size(); ++i) + S[i] = S[i-1] + 0x9E3779B9; + + SecureVector K(8); + + for(s32bit i = length-1; i >= 0; --i) + K[i/4] = (K[i/4] << 8) + key[i]; + + u32bit A = 0, B = 0; + for(size_t i = 0; i != MIX_ROUNDS; ++i) + { + A = rotate_left(S[i % S.size()] + A + B, 3); + B = rotate_left(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32); + S[i % S.size()] = A; + K[i % WORD_KEYLENGTH] = B; + } + } + +} +/* +* SAFER-SK +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +const byte EXP[256] = { + 0x01, 0x2D, 0xE2, 0x93, 0xBE, 0x45, 0x15, 0xAE, 0x78, 0x03, 0x87, 0xA4, + 0xB8, 0x38, 0xCF, 0x3F, 0x08, 0x67, 0x09, 0x94, 0xEB, 0x26, 0xA8, 0x6B, + 0xBD, 0x18, 0x34, 0x1B, 0xBB, 0xBF, 0x72, 0xF7, 0x40, 0x35, 0x48, 0x9C, + 0x51, 0x2F, 0x3B, 0x55, 0xE3, 0xC0, 0x9F, 0xD8, 0xD3, 0xF3, 0x8D, 0xB1, + 0xFF, 0xA7, 0x3E, 0xDC, 0x86, 0x77, 0xD7, 0xA6, 0x11, 0xFB, 0xF4, 0xBA, + 0x92, 0x91, 0x64, 0x83, 0xF1, 0x33, 0xEF, 0xDA, 0x2C, 0xB5, 0xB2, 0x2B, + 0x88, 0xD1, 0x99, 0xCB, 0x8C, 0x84, 0x1D, 0x14, 0x81, 0x97, 0x71, 0xCA, + 0x5F, 0xA3, 0x8B, 0x57, 0x3C, 0x82, 0xC4, 0x52, 0x5C, 0x1C, 0xE8, 0xA0, + 0x04, 0xB4, 0x85, 0x4A, 0xF6, 0x13, 0x54, 0xB6, 0xDF, 0x0C, 0x1A, 0x8E, + 0xDE, 0xE0, 0x39, 0xFC, 0x20, 0x9B, 0x24, 0x4E, 0xA9, 0x98, 0x9E, 0xAB, + 0xF2, 0x60, 0xD0, 0x6C, 0xEA, 0xFA, 0xC7, 0xD9, 0x00, 0xD4, 0x1F, 0x6E, + 0x43, 0xBC, 0xEC, 0x53, 0x89, 0xFE, 0x7A, 0x5D, 0x49, 0xC9, 0x32, 0xC2, + 0xF9, 0x9A, 0xF8, 0x6D, 0x16, 0xDB, 0x59, 0x96, 0x44, 0xE9, 0xCD, 0xE6, + 0x46, 0x42, 0x8F, 0x0A, 0xC1, 0xCC, 0xB9, 0x65, 0xB0, 0xD2, 0xC6, 0xAC, + 0x1E, 0x41, 0x62, 0x29, 0x2E, 0x0E, 0x74, 0x50, 0x02, 0x5A, 0xC3, 0x25, + 0x7B, 0x8A, 0x2A, 0x5B, 0xF0, 0x06, 0x0D, 0x47, 0x6F, 0x70, 0x9D, 0x7E, + 0x10, 0xCE, 0x12, 0x27, 0xD5, 0x4C, 0x4F, 0xD6, 0x79, 0x30, 0x68, 0x36, + 0x75, 0x7D, 0xE4, 0xED, 0x80, 0x6A, 0x90, 0x37, 0xA2, 0x5E, 0x76, 0xAA, + 0xC5, 0x7F, 0x3D, 0xAF, 0xA5, 0xE5, 0x19, 0x61, 0xFD, 0x4D, 0x7C, 0xB7, + 0x0B, 0xEE, 0xAD, 0x4B, 0x22, 0xF5, 0xE7, 0x73, 0x23, 0x21, 0xC8, 0x05, + 0xE1, 0x66, 0xDD, 0xB3, 0x58, 0x69, 0x63, 0x56, 0x0F, 0xA1, 0x31, 0x95, + 0x17, 0x07, 0x3A, 0x28 }; + +const byte LOG[512] = { + 0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD, 0x10, 0x12, 0x9F, 0xE4, + 0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65, 0x4F, 0x06, 0x94, 0xFC, + 0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82, 0x70, 0xED, 0xE8, 0xEC, + 0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47, 0x44, 0x01, 0xAC, 0x25, + 0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3, 0x0D, 0x6E, 0xFE, 0x26, + 0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84, 0x98, 0x05, 0x9C, 0xBB, + 0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6, 0xAF, 0x24, 0x5B, 0x87, + 0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7, 0x5C, 0x8B, 0xD5, 0x54, + 0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11, 0xCA, 0xF5, 0xD1, 0x17, + 0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB, 0xAE, 0xCC, 0xD6, 0x35, + 0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9, 0xD0, 0x50, 0x59, 0x3F, + 0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56, 0x4C, 0x2E, 0x6B, 0x9E, + 0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51, 0x75, 0x4A, 0x91, 0x71, + 0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55, 0x0B, 0xDC, 0x37, 0x31, + 0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB, 0xA4, 0x2F, 0x46, 0xF3, + 0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C, 0x85, 0x18, 0x04, 0x1D, + 0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E, 0xEE, 0x8D, 0x53, 0x4B, + 0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C, 0x81, 0xC4, 0xC7, 0x36, + 0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68, 0x6D, 0xF0, 0x02, 0x28, + 0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14, 0x86, 0xCF, 0xE5, 0x42, + 0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F, 0x92, 0x90, 0x7D, 0x39, + 0x6F, 0xE0, 0x89, 0x30, 0x80, 0x00, 0xB0, 0x09, 0x60, 0xEF, 0xB9, 0xFD, + 0x10, 0x12, 0x9F, 0xE4, 0x69, 0xBA, 0xAD, 0xF8, 0xC0, 0x38, 0xC2, 0x65, + 0x4F, 0x06, 0x94, 0xFC, 0x19, 0xDE, 0x6A, 0x1B, 0x5D, 0x4E, 0xA8, 0x82, + 0x70, 0xED, 0xE8, 0xEC, 0x72, 0xB3, 0x15, 0xC3, 0xFF, 0xAB, 0xB6, 0x47, + 0x44, 0x01, 0xAC, 0x25, 0xC9, 0xFA, 0x8E, 0x41, 0x1A, 0x21, 0xCB, 0xD3, + 0x0D, 0x6E, 0xFE, 0x26, 0x58, 0xDA, 0x32, 0x0F, 0x20, 0xA9, 0x9D, 0x84, + 0x98, 0x05, 0x9C, 0xBB, 0x22, 0x8C, 0x63, 0xE7, 0xC5, 0xE1, 0x73, 0xC6, + 0xAF, 0x24, 0x5B, 0x87, 0x66, 0x27, 0xF7, 0x57, 0xF4, 0x96, 0xB1, 0xB7, + 0x5C, 0x8B, 0xD5, 0x54, 0x79, 0xDF, 0xAA, 0xF6, 0x3E, 0xA3, 0xF1, 0x11, + 0xCA, 0xF5, 0xD1, 0x17, 0x7B, 0x93, 0x83, 0xBC, 0xBD, 0x52, 0x1E, 0xEB, + 0xAE, 0xCC, 0xD6, 0x35, 0x08, 0xC8, 0x8A, 0xB4, 0xE2, 0xCD, 0xBF, 0xD9, + 0xD0, 0x50, 0x59, 0x3F, 0x4D, 0x62, 0x34, 0x0A, 0x48, 0x88, 0xB5, 0x56, + 0x4C, 0x2E, 0x6B, 0x9E, 0xD2, 0x3D, 0x3C, 0x03, 0x13, 0xFB, 0x97, 0x51, + 0x75, 0x4A, 0x91, 0x71, 0x23, 0xBE, 0x76, 0x2A, 0x5F, 0xF9, 0xD4, 0x55, + 0x0B, 0xDC, 0x37, 0x31, 0x16, 0x74, 0xD7, 0x77, 0xA7, 0xE6, 0x07, 0xDB, + 0xA4, 0x2F, 0x46, 0xF3, 0x61, 0x45, 0x67, 0xE3, 0x0C, 0xA2, 0x3B, 0x1C, + 0x85, 0x18, 0x04, 0x1D, 0x29, 0xA0, 0x8F, 0xB2, 0x5A, 0xD8, 0xA6, 0x7E, + 0xEE, 0x8D, 0x53, 0x4B, 0xA1, 0x9A, 0xC1, 0x0E, 0x7A, 0x49, 0xA5, 0x2C, + 0x81, 0xC4, 0xC7, 0x36, 0x2B, 0x7F, 0x43, 0x95, 0x33, 0xF2, 0x6C, 0x68, + 0x6D, 0xF0, 0x02, 0x28, 0xCE, 0xDD, 0x9B, 0xEA, 0x5E, 0x99, 0x7C, 0x14, + 0x86, 0xCF, 0xE5, 0x42, 0xB8, 0x40, 0x78, 0x2D, 0x3A, 0xE9, 0x64, 0x1F, + 0x92, 0x90, 0x7D, 0x39, 0x6F, 0xE0, 0x89, 0x30 }; + +} + +/* +* SAFER-SK Encryption +*/ +void SAFER_SK::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t rounds = get_rounds(); + + for(size_t i = 0; i != blocks; ++i) + { + byte A = in[0], B = in[1], C = in[2], D = in[3], + E = in[4], F = in[5], G = in[6], H = in[7], X, Y; + + for(size_t j = 0; j != 16*rounds; j += 16) + { + A = EXP[A ^ EK[j ]]; B = LOG[B + EK[j+1]]; + C = LOG[C + EK[j+2]]; D = EXP[D ^ EK[j+3]]; + E = EXP[E ^ EK[j+4]]; F = LOG[F + EK[j+5]]; + G = LOG[G + EK[j+6]]; H = EXP[H ^ EK[j+7]]; + + A += EK[j+ 8]; B ^= EK[j+ 9]; C ^= EK[j+10]; D += EK[j+11]; + E += EK[j+12]; F ^= EK[j+13]; G ^= EK[j+14]; H += EK[j+15]; + + B += A; D += C; F += E; H += G; A += B; C += D; E += F; G += H; + C += A; G += E; D += B; H += F; A += C; E += G; B += D; F += H; + H += D; Y = D + H; D = B + F; X = B + D; B = A + E; + A += B; F = C + G; E = C + F; C = X; G = Y; + } + + out[0] = A ^ EK[16*rounds+0]; out[1] = B + EK[16*rounds+1]; + out[2] = C + EK[16*rounds+2]; out[3] = D ^ EK[16*rounds+3]; + out[4] = E ^ EK[16*rounds+4]; out[5] = F + EK[16*rounds+5]; + out[6] = G + EK[16*rounds+6]; out[7] = H ^ EK[16*rounds+7]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SAFER-SK Decryption +*/ +void SAFER_SK::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const size_t rounds = get_rounds(); + + for(size_t i = 0; i != blocks; ++i) + { + byte A = in[0], B = in[1], C = in[2], D = in[3], + E = in[4], F = in[5], G = in[6], H = in[7]; + + A ^= EK[16*rounds+0]; B -= EK[16*rounds+1]; C -= EK[16*rounds+2]; + D ^= EK[16*rounds+3]; E ^= EK[16*rounds+4]; F -= EK[16*rounds+5]; + G -= EK[16*rounds+6]; H ^= EK[16*rounds+7]; + + for(s32bit j = 16*(rounds-1); j >= 0; j -= 16) + { + byte T = E; E = B; B = C; C = T; T = F; F = D; D = G; G = T; + A -= E; B -= F; C -= G; D -= H; E -= A; F -= B; G -= C; H -= D; + A -= C; E -= G; B -= D; F -= H; C -= A; G -= E; D -= B; H -= F; + A -= B; C -= D; E -= F; G -= H; B -= A; D -= C; F -= E; H -= G; + + A = LOG[A - EK[j+8 ] + 256]; B = EXP[B ^ EK[j+9 ]]; + C = EXP[C ^ EK[j+10]]; D = LOG[D - EK[j+11] + 256]; + E = LOG[E - EK[j+12] + 256]; F = EXP[F ^ EK[j+13]]; + G = EXP[G ^ EK[j+14]]; H = LOG[H - EK[j+15] + 256]; + + A ^= EK[j+0]; B -= EK[j+1]; C -= EK[j+2]; D ^= EK[j+3]; + E ^= EK[j+4]; F -= EK[j+5]; G -= EK[j+6]; H ^= EK[j+7]; + } + + out[0] = A; out[1] = B; out[2] = C; out[3] = D; + out[4] = E; out[5] = F; out[6] = G; out[7] = H; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SAFER-SK Key Schedule +*/ +void SAFER_SK::key_schedule(const byte key[], size_t) + { + const byte BIAS[208] = { + 0x16, 0x73, 0x3B, 0x1E, 0x8E, 0x70, 0xBD, 0x86, 0x47, 0x7E, 0x24, 0x56, + 0xF1, 0x77, 0x88, 0x46, 0xB1, 0xBA, 0xA3, 0xB7, 0x10, 0x0A, 0xC5, 0x37, + 0xC9, 0x5A, 0x28, 0xAC, 0x64, 0xA5, 0xEC, 0xAB, 0xC6, 0x67, 0x95, 0x58, + 0x0D, 0xF8, 0x9A, 0xF6, 0x66, 0xDC, 0x05, 0x3D, 0xD3, 0x8A, 0xC3, 0xD8, + 0x6A, 0xE9, 0x36, 0x49, 0x43, 0xBF, 0xEB, 0xD4, 0x9B, 0x68, 0xA0, 0x65, + 0x5D, 0x57, 0x92, 0x1F, 0x71, 0x5C, 0xBB, 0x22, 0xC1, 0xBE, 0x7B, 0xBC, + 0x63, 0x94, 0x5F, 0x2A, 0x61, 0xB8, 0x34, 0x32, 0xFD, 0xFB, 0x17, 0x40, + 0xE6, 0x51, 0x1D, 0x41, 0x8F, 0x29, 0xDD, 0x04, 0x80, 0xDE, 0xE7, 0x31, + 0x7F, 0x01, 0xA2, 0xF7, 0x39, 0xDA, 0x6F, 0x23, 0xFE, 0x3A, 0xD0, 0x1C, + 0xD1, 0x30, 0x3E, 0x12, 0xCD, 0x0F, 0xE0, 0xA8, 0xAF, 0x82, 0x59, 0x2C, + 0x7D, 0xAD, 0xB2, 0xEF, 0xC2, 0x87, 0xCE, 0x75, 0x13, 0x02, 0x90, 0x4F, + 0x2E, 0x72, 0x33, 0x85, 0x8D, 0xCF, 0xA9, 0x81, 0xE2, 0xC4, 0x27, 0x2F, + 0x7A, 0x9F, 0x52, 0xE1, 0x15, 0x38, 0x2B, 0xFC, 0x42, 0xC7, 0x08, 0xE4, + 0x09, 0x55, 0x5E, 0x8C, 0x76, 0x60, 0xFF, 0xDF, 0xD7, 0x98, 0xFA, 0x0B, + 0x00, 0x1A, 0xF9, 0xA6, 0xB9, 0xE8, 0x9E, 0x62, 0xD9, 0x91, 0x50, 0xD2, + 0xEE, 0x18, 0xB4, 0x07, 0xEA, 0x5B, 0xA4, 0xC8, 0x0E, 0xCB, 0x48, 0x69, + 0x4E, 0x9C, 0x35, 0x79, 0x45, 0x4D, 0x54, 0xE5, 0x3C, 0x0C, 0x4A, 0x8B, + 0x3F, 0xCC, 0xA7, 0xDB }; + + const byte KEY_INDEX[208] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x00, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x0E, 0x0F, 0x10, 0x11, + 0x09, 0x0A, 0x0B, 0x0C, 0x06, 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x08, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x09, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x01, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, + 0x00, 0x01, 0x02, 0x03, 0x0F, 0x10, 0x11, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x07, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F }; + + SecureVector KB(18); + + for(size_t i = 0; i != 8; ++i) + { + KB[ 8] ^= KB[i] = rotate_left(key[i], 5); + KB[17] ^= KB[i+9] = EK[i] = key[i+8]; + } + + for(size_t i = 0; i != get_rounds(); ++i) + { + for(size_t j = 0; j != 18; ++j) + KB[j] = rotate_left(KB[j], 6); + for(size_t j = 0; j != 16; ++j) + EK[16*i+j+8] = KB[KEY_INDEX[16*i+j]] + BIAS[16*i+j]; + } + } + +/* +* Return the name of this type +*/ +std::string SAFER_SK::name() const + { + return "SAFER-SK(" + to_string(get_rounds()) + ")"; + } + +/* +* Return a clone of this object +*/ +BlockCipher* SAFER_SK::clone() const + { + return new SAFER_SK(get_rounds()); + } + +/* +* SAFER-SK Constructor +*/ +SAFER_SK::SAFER_SK(size_t rounds) + { + if(rounds > 13 || rounds == 0) + throw Invalid_Argument(name() + ": Invalid number of rounds"); + + EK.resize(16 * rounds + 8); + } + +} +/* +* SEED +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* SEED G Function +*/ +u32bit SEED::G_FUNC::operator()(u32bit X) const + { + return (S0[get_byte(3, X)] ^ S1[get_byte(2, X)] ^ + S2[get_byte(1, X)] ^ S3[get_byte(0, X)]); + } + +/* +* SEED Encryption +*/ +void SEED::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_be(in, 0); + u32bit B1 = load_be(in, 1); + u32bit B2 = load_be(in, 2); + u32bit B3 = load_be(in, 3); + + G_FUNC G; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit T0, T1; + + T0 = B2 ^ K[2*j]; + T1 = G(B2 ^ B3 ^ K[2*j+1]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ K[2*j+2]; + T1 = G(B0 ^ B1 ^ K[2*j+3]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Decryption +*/ +void SEED::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_be(in, 0); + u32bit B1 = load_be(in, 1); + u32bit B2 = load_be(in, 2); + u32bit B3 = load_be(in, 3); + + G_FUNC G; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit T0, T1; + + T0 = B2 ^ K[30-2*j]; + T1 = G(B2 ^ B3 ^ K[31-2*j]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ K[28-2*j]; + T1 = G(B0 ^ B1 ^ K[29-2*j]); + T0 = G(T1 + T0); + T1 = G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Key Schedule +*/ +void SEED::key_schedule(const byte key[], size_t) + { + const u32bit RC[16] = { + 0x9E3779B9, 0x3C6EF373, 0x78DDE6E6, 0xF1BBCDCC, + 0xE3779B99, 0xC6EF3733, 0x8DDE6E67, 0x1BBCDCCF, + 0x3779B99E, 0x6EF3733C, 0xDDE6E678, 0xBBCDCCF1, + 0x779B99E3, 0xEF3733C6, 0xDE6E678D, 0xBCDCCF1B + }; + + SecureVector WK(4); + + for(size_t i = 0; i != 4; ++i) + WK[i] = load_be(key, i); + + G_FUNC G; + + for(size_t i = 0; i != 16; i += 2) + { + K[2*i ] = G(WK[0] + WK[2] - RC[i]); + K[2*i+1] = G(WK[1] - WK[3] + RC[i]) ^ K[2*i]; + + byte T = get_byte(3, WK[0]); + WK[0] = (WK[0] >> 8) | (get_byte(3, WK[1]) << 24); + WK[1] = (WK[1] >> 8) | (T << 24); + + K[2*i+2] = G(WK[0] + WK[2] - RC[i+1]); + K[2*i+3] = G(WK[1] - WK[3] + RC[i+1]) ^ K[2*i+2]; + + T = get_byte(0, WK[3]); + WK[3] = (WK[3] << 8) | get_byte(0, WK[2]); + WK[2] = (WK[2] << 8) | T; + } + } + +} +/* +* S-Box Tables for SEED +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u32bit SEED::G_FUNC::S0[256] = { + 0x2989A1A8, 0x05858184, 0x16C6D2D4, 0x13C3D3D0, 0x14445054, 0x1D0D111C, + 0x2C8CA0AC, 0x25052124, 0x1D4D515C, 0x03434340, 0x18081018, 0x1E0E121C, + 0x11415150, 0x3CCCF0FC, 0x0ACAC2C8, 0x23436360, 0x28082028, 0x04444044, + 0x20002020, 0x1D8D919C, 0x20C0E0E0, 0x22C2E2E0, 0x08C8C0C8, 0x17071314, + 0x2585A1A4, 0x0F8F838C, 0x03030300, 0x3B4B7378, 0x3B8BB3B8, 0x13031310, + 0x12C2D2D0, 0x2ECEE2EC, 0x30407070, 0x0C8C808C, 0x3F0F333C, 0x2888A0A8, + 0x32023230, 0x1DCDD1DC, 0x36C6F2F4, 0x34447074, 0x2CCCE0EC, 0x15859194, + 0x0B0B0308, 0x17475354, 0x1C4C505C, 0x1B4B5358, 0x3D8DB1BC, 0x01010100, + 0x24042024, 0x1C0C101C, 0x33437370, 0x18889098, 0x10001010, 0x0CCCC0CC, + 0x32C2F2F0, 0x19C9D1D8, 0x2C0C202C, 0x27C7E3E4, 0x32427270, 0x03838380, + 0x1B8B9398, 0x11C1D1D0, 0x06868284, 0x09C9C1C8, 0x20406060, 0x10405050, + 0x2383A3A0, 0x2BCBE3E8, 0x0D0D010C, 0x3686B2B4, 0x1E8E929C, 0x0F4F434C, + 0x3787B3B4, 0x1A4A5258, 0x06C6C2C4, 0x38487078, 0x2686A2A4, 0x12021210, + 0x2F8FA3AC, 0x15C5D1D4, 0x21416160, 0x03C3C3C0, 0x3484B0B4, 0x01414140, + 0x12425250, 0x3D4D717C, 0x0D8D818C, 0x08080008, 0x1F0F131C, 0x19899198, + 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37C7F3F4, 0x21C1E1E0, + 0x3DCDF1FC, 0x36467274, 0x2F0F232C, 0x27072324, 0x3080B0B0, 0x0B8B8388, + 0x0E0E020C, 0x2B8BA3A8, 0x2282A2A0, 0x2E4E626C, 0x13839390, 0x0D4D414C, + 0x29496168, 0x3C4C707C, 0x09090108, 0x0A0A0208, 0x3F8FB3BC, 0x2FCFE3EC, + 0x33C3F3F0, 0x05C5C1C4, 0x07878384, 0x14041014, 0x3ECEF2FC, 0x24446064, + 0x1ECED2DC, 0x2E0E222C, 0x0B4B4348, 0x1A0A1218, 0x06060204, 0x21012120, + 0x2B4B6368, 0x26466264, 0x02020200, 0x35C5F1F4, 0x12829290, 0x0A8A8288, + 0x0C0C000C, 0x3383B3B0, 0x3E4E727C, 0x10C0D0D0, 0x3A4A7278, 0x07474344, + 0x16869294, 0x25C5E1E4, 0x26062224, 0x00808080, 0x2D8DA1AC, 0x1FCFD3DC, + 0x2181A1A0, 0x30003030, 0x37073334, 0x2E8EA2AC, 0x36063234, 0x15051114, + 0x22022220, 0x38083038, 0x34C4F0F4, 0x2787A3A4, 0x05454144, 0x0C4C404C, + 0x01818180, 0x29C9E1E8, 0x04848084, 0x17879394, 0x35053134, 0x0BCBC3C8, + 0x0ECEC2CC, 0x3C0C303C, 0x31417170, 0x11011110, 0x07C7C3C4, 0x09898188, + 0x35457174, 0x3BCBF3F8, 0x1ACAD2D8, 0x38C8F0F8, 0x14849094, 0x19495158, + 0x02828280, 0x04C4C0C4, 0x3FCFF3FC, 0x09494148, 0x39093138, 0x27476364, + 0x00C0C0C0, 0x0FCFC3CC, 0x17C7D3D4, 0x3888B0B8, 0x0F0F030C, 0x0E8E828C, + 0x02424240, 0x23032320, 0x11819190, 0x2C4C606C, 0x1BCBD3D8, 0x2484A0A4, + 0x34043034, 0x31C1F1F0, 0x08484048, 0x02C2C2C0, 0x2F4F636C, 0x3D0D313C, + 0x2D0D212C, 0x00404040, 0x3E8EB2BC, 0x3E0E323C, 0x3C8CB0BC, 0x01C1C1C0, + 0x2A8AA2A8, 0x3A8AB2B8, 0x0E4E424C, 0x15455154, 0x3B0B3338, 0x1CCCD0DC, + 0x28486068, 0x3F4F737C, 0x1C8C909C, 0x18C8D0D8, 0x0A4A4248, 0x16465254, + 0x37477374, 0x2080A0A0, 0x2DCDE1EC, 0x06464244, 0x3585B1B4, 0x2B0B2328, + 0x25456164, 0x3ACAF2F8, 0x23C3E3E0, 0x3989B1B8, 0x3181B1B0, 0x1F8F939C, + 0x1E4E525C, 0x39C9F1F8, 0x26C6E2E4, 0x3282B2B0, 0x31013130, 0x2ACAE2E8, + 0x2D4D616C, 0x1F4F535C, 0x24C4E0E4, 0x30C0F0F0, 0x0DCDC1CC, 0x08888088, + 0x16061214, 0x3A0A3238, 0x18485058, 0x14C4D0D4, 0x22426260, 0x29092128, + 0x07070304, 0x33033330, 0x28C8E0E8, 0x1B0B1318, 0x05050104, 0x39497178, + 0x10809090, 0x2A4A6268, 0x2A0A2228, 0x1A8A9298 }; + +const u32bit SEED::G_FUNC::S1[256] = { + 0x38380830, 0xE828C8E0, 0x2C2D0D21, 0xA42686A2, 0xCC0FCFC3, 0xDC1ECED2, + 0xB03383B3, 0xB83888B0, 0xAC2F8FA3, 0x60204060, 0x54154551, 0xC407C7C3, + 0x44044440, 0x6C2F4F63, 0x682B4B63, 0x581B4B53, 0xC003C3C3, 0x60224262, + 0x30330333, 0xB43585B1, 0x28290921, 0xA02080A0, 0xE022C2E2, 0xA42787A3, + 0xD013C3D3, 0x90118191, 0x10110111, 0x04060602, 0x1C1C0C10, 0xBC3C8CB0, + 0x34360632, 0x480B4B43, 0xEC2FCFE3, 0x88088880, 0x6C2C4C60, 0xA82888A0, + 0x14170713, 0xC404C4C0, 0x14160612, 0xF434C4F0, 0xC002C2C2, 0x44054541, + 0xE021C1E1, 0xD416C6D2, 0x3C3F0F33, 0x3C3D0D31, 0x8C0E8E82, 0x98188890, + 0x28280820, 0x4C0E4E42, 0xF436C6F2, 0x3C3E0E32, 0xA42585A1, 0xF839C9F1, + 0x0C0D0D01, 0xDC1FCFD3, 0xD818C8D0, 0x282B0B23, 0x64264662, 0x783A4A72, + 0x24270723, 0x2C2F0F23, 0xF031C1F1, 0x70324272, 0x40024242, 0xD414C4D0, + 0x40014141, 0xC000C0C0, 0x70334373, 0x64274763, 0xAC2C8CA0, 0x880B8B83, + 0xF437C7F3, 0xAC2D8DA1, 0x80008080, 0x1C1F0F13, 0xC80ACAC2, 0x2C2C0C20, + 0xA82A8AA2, 0x34340430, 0xD012C2D2, 0x080B0B03, 0xEC2ECEE2, 0xE829C9E1, + 0x5C1D4D51, 0x94148490, 0x18180810, 0xF838C8F0, 0x54174753, 0xAC2E8EA2, + 0x08080800, 0xC405C5C1, 0x10130313, 0xCC0DCDC1, 0x84068682, 0xB83989B1, + 0xFC3FCFF3, 0x7C3D4D71, 0xC001C1C1, 0x30310131, 0xF435C5F1, 0x880A8A82, + 0x682A4A62, 0xB03181B1, 0xD011C1D1, 0x20200020, 0xD417C7D3, 0x00020202, + 0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xD81BCBD3, + 0x9C1D8D91, 0x98198991, 0x60214161, 0xBC3E8EB2, 0xE426C6E2, 0x58194951, + 0xDC1DCDD1, 0x50114151, 0x90108090, 0xDC1CCCD0, 0x981A8A92, 0xA02383A3, + 0xA82B8BA3, 0xD010C0D0, 0x80018181, 0x0C0F0F03, 0x44074743, 0x181A0A12, + 0xE023C3E3, 0xEC2CCCE0, 0x8C0D8D81, 0xBC3F8FB3, 0x94168692, 0x783B4B73, + 0x5C1C4C50, 0xA02282A2, 0xA02181A1, 0x60234363, 0x20230323, 0x4C0D4D41, + 0xC808C8C0, 0x9C1E8E92, 0x9C1C8C90, 0x383A0A32, 0x0C0C0C00, 0x2C2E0E22, + 0xB83A8AB2, 0x6C2E4E62, 0x9C1F8F93, 0x581A4A52, 0xF032C2F2, 0x90128292, + 0xF033C3F3, 0x48094941, 0x78384870, 0xCC0CCCC0, 0x14150511, 0xF83BCBF3, + 0x70304070, 0x74354571, 0x7C3F4F73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6C2D4D61, 0xC406C6C2, 0x74344470, 0xD415C5D1, 0xB43484B0, + 0xE82ACAE2, 0x08090901, 0x74364672, 0x18190911, 0xFC3ECEF2, 0x40004040, + 0x10120212, 0xE020C0E0, 0xBC3D8DB1, 0x04050501, 0xF83ACAF2, 0x00010101, + 0xF030C0F0, 0x282A0A22, 0x5C1E4E52, 0xA82989A1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981B8B93, 0xB03080B0, 0xE425C5E1, + 0x48084840, 0x78394971, 0x94178793, 0xFC3CCCF0, 0x1C1E0E12, 0x80028282, + 0x20210121, 0x8C0C8C80, 0x181B0B13, 0x5C1F4F53, 0x74374773, 0x54144450, + 0xB03282B2, 0x1C1D0D11, 0x24250521, 0x4C0F4F43, 0x00000000, 0x44064642, + 0xEC2DCDE1, 0x58184850, 0x50124252, 0xE82BCBE3, 0x7C3E4E72, 0xD81ACAD2, + 0xC809C9C1, 0xFC3DCDF1, 0x30300030, 0x94158591, 0x64254561, 0x3C3C0C30, + 0xB43686B2, 0xE424C4E0, 0xB83B8BB3, 0x7C3C4C70, 0x0C0E0E02, 0x50104050, + 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xE427C7E3, 0x24240420, 0xA42484A0, 0xC80BCBC3, 0x50134353, + 0x080A0A02, 0x84078783, 0xD819C9D1, 0x4C0C4C40, 0x80038383, 0x8C0F8F83, + 0xCC0ECEC2, 0x383B0B33, 0x480A4A42, 0xB43787B3 }; + +const u32bit SEED::G_FUNC::S2[256] = { + 0xA1A82989, 0x81840585, 0xD2D416C6, 0xD3D013C3, 0x50541444, 0x111C1D0D, + 0xA0AC2C8C, 0x21242505, 0x515C1D4D, 0x43400343, 0x10181808, 0x121C1E0E, + 0x51501141, 0xF0FC3CCC, 0xC2C80ACA, 0x63602343, 0x20282808, 0x40440444, + 0x20202000, 0x919C1D8D, 0xE0E020C0, 0xE2E022C2, 0xC0C808C8, 0x13141707, + 0xA1A42585, 0x838C0F8F, 0x03000303, 0x73783B4B, 0xB3B83B8B, 0x13101303, + 0xD2D012C2, 0xE2EC2ECE, 0x70703040, 0x808C0C8C, 0x333C3F0F, 0xA0A82888, + 0x32303202, 0xD1DC1DCD, 0xF2F436C6, 0x70743444, 0xE0EC2CCC, 0x91941585, + 0x03080B0B, 0x53541747, 0x505C1C4C, 0x53581B4B, 0xB1BC3D8D, 0x01000101, + 0x20242404, 0x101C1C0C, 0x73703343, 0x90981888, 0x10101000, 0xC0CC0CCC, + 0xF2F032C2, 0xD1D819C9, 0x202C2C0C, 0xE3E427C7, 0x72703242, 0x83800383, + 0x93981B8B, 0xD1D011C1, 0x82840686, 0xC1C809C9, 0x60602040, 0x50501040, + 0xA3A02383, 0xE3E82BCB, 0x010C0D0D, 0xB2B43686, 0x929C1E8E, 0x434C0F4F, + 0xB3B43787, 0x52581A4A, 0xC2C406C6, 0x70783848, 0xA2A42686, 0x12101202, + 0xA3AC2F8F, 0xD1D415C5, 0x61602141, 0xC3C003C3, 0xB0B43484, 0x41400141, + 0x52501242, 0x717C3D4D, 0x818C0D8D, 0x00080808, 0x131C1F0F, 0x91981989, + 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xF3F437C7, 0xE1E021C1, + 0xF1FC3DCD, 0x72743646, 0x232C2F0F, 0x23242707, 0xB0B03080, 0x83880B8B, + 0x020C0E0E, 0xA3A82B8B, 0xA2A02282, 0x626C2E4E, 0x93901383, 0x414C0D4D, + 0x61682949, 0x707C3C4C, 0x01080909, 0x02080A0A, 0xB3BC3F8F, 0xE3EC2FCF, + 0xF3F033C3, 0xC1C405C5, 0x83840787, 0x10141404, 0xF2FC3ECE, 0x60642444, + 0xD2DC1ECE, 0x222C2E0E, 0x43480B4B, 0x12181A0A, 0x02040606, 0x21202101, + 0x63682B4B, 0x62642646, 0x02000202, 0xF1F435C5, 0x92901282, 0x82880A8A, + 0x000C0C0C, 0xB3B03383, 0x727C3E4E, 0xD0D010C0, 0x72783A4A, 0x43440747, + 0x92941686, 0xE1E425C5, 0x22242606, 0x80800080, 0xA1AC2D8D, 0xD3DC1FCF, + 0xA1A02181, 0x30303000, 0x33343707, 0xA2AC2E8E, 0x32343606, 0x11141505, + 0x22202202, 0x30383808, 0xF0F434C4, 0xA3A42787, 0x41440545, 0x404C0C4C, + 0x81800181, 0xE1E829C9, 0x80840484, 0x93941787, 0x31343505, 0xC3C80BCB, + 0xC2CC0ECE, 0x303C3C0C, 0x71703141, 0x11101101, 0xC3C407C7, 0x81880989, + 0x71743545, 0xF3F83BCB, 0xD2D81ACA, 0xF0F838C8, 0x90941484, 0x51581949, + 0x82800282, 0xC0C404C4, 0xF3FC3FCF, 0x41480949, 0x31383909, 0x63642747, + 0xC0C000C0, 0xC3CC0FCF, 0xD3D417C7, 0xB0B83888, 0x030C0F0F, 0x828C0E8E, + 0x42400242, 0x23202303, 0x91901181, 0x606C2C4C, 0xD3D81BCB, 0xA0A42484, + 0x30343404, 0xF1F031C1, 0x40480848, 0xC2C002C2, 0x636C2F4F, 0x313C3D0D, + 0x212C2D0D, 0x40400040, 0xB2BC3E8E, 0x323C3E0E, 0xB0BC3C8C, 0xC1C001C1, + 0xA2A82A8A, 0xB2B83A8A, 0x424C0E4E, 0x51541545, 0x33383B0B, 0xD0DC1CCC, + 0x60682848, 0x737C3F4F, 0x909C1C8C, 0xD0D818C8, 0x42480A4A, 0x52541646, + 0x73743747, 0xA0A02080, 0xE1EC2DCD, 0x42440646, 0xB1B43585, 0x23282B0B, + 0x61642545, 0xF2F83ACA, 0xE3E023C3, 0xB1B83989, 0xB1B03181, 0x939C1F8F, + 0x525C1E4E, 0xF1F839C9, 0xE2E426C6, 0xB2B03282, 0x31303101, 0xE2E82ACA, + 0x616C2D4D, 0x535C1F4F, 0xE0E424C4, 0xF0F030C0, 0xC1CC0DCD, 0x80880888, + 0x12141606, 0x32383A0A, 0x50581848, 0xD0D414C4, 0x62602242, 0x21282909, + 0x03040707, 0x33303303, 0xE0E828C8, 0x13181B0B, 0x01040505, 0x71783949, + 0x90901080, 0x62682A4A, 0x22282A0A, 0x92981A8A }; + +const u32bit SEED::G_FUNC::S3[256] = { + 0x08303838, 0xC8E0E828, 0x0D212C2D, 0x86A2A426, 0xCFC3CC0F, 0xCED2DC1E, + 0x83B3B033, 0x88B0B838, 0x8FA3AC2F, 0x40606020, 0x45515415, 0xC7C3C407, + 0x44404404, 0x4F636C2F, 0x4B63682B, 0x4B53581B, 0xC3C3C003, 0x42626022, + 0x03333033, 0x85B1B435, 0x09212829, 0x80A0A020, 0xC2E2E022, 0x87A3A427, + 0xC3D3D013, 0x81919011, 0x01111011, 0x06020406, 0x0C101C1C, 0x8CB0BC3C, + 0x06323436, 0x4B43480B, 0xCFE3EC2F, 0x88808808, 0x4C606C2C, 0x88A0A828, + 0x07131417, 0xC4C0C404, 0x06121416, 0xC4F0F434, 0xC2C2C002, 0x45414405, + 0xC1E1E021, 0xC6D2D416, 0x0F333C3F, 0x0D313C3D, 0x8E828C0E, 0x88909818, + 0x08202828, 0x4E424C0E, 0xC6F2F436, 0x0E323C3E, 0x85A1A425, 0xC9F1F839, + 0x0D010C0D, 0xCFD3DC1F, 0xC8D0D818, 0x0B23282B, 0x46626426, 0x4A72783A, + 0x07232427, 0x0F232C2F, 0xC1F1F031, 0x42727032, 0x42424002, 0xC4D0D414, + 0x41414001, 0xC0C0C000, 0x43737033, 0x47636427, 0x8CA0AC2C, 0x8B83880B, + 0xC7F3F437, 0x8DA1AC2D, 0x80808000, 0x0F131C1F, 0xCAC2C80A, 0x0C202C2C, + 0x8AA2A82A, 0x04303434, 0xC2D2D012, 0x0B03080B, 0xCEE2EC2E, 0xC9E1E829, + 0x4D515C1D, 0x84909414, 0x08101818, 0xC8F0F838, 0x47535417, 0x8EA2AC2E, + 0x08000808, 0xC5C1C405, 0x03131013, 0xCDC1CC0D, 0x86828406, 0x89B1B839, + 0xCFF3FC3F, 0x4D717C3D, 0xC1C1C001, 0x01313031, 0xC5F1F435, 0x8A82880A, + 0x4A62682A, 0x81B1B031, 0xC1D1D011, 0x00202020, 0xC7D3D417, 0x02020002, + 0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xCBD3D81B, + 0x8D919C1D, 0x89919819, 0x41616021, 0x8EB2BC3E, 0xC6E2E426, 0x49515819, + 0xCDD1DC1D, 0x41515011, 0x80909010, 0xCCD0DC1C, 0x8A92981A, 0x83A3A023, + 0x8BA3A82B, 0xC0D0D010, 0x81818001, 0x0F030C0F, 0x47434407, 0x0A12181A, + 0xC3E3E023, 0xCCE0EC2C, 0x8D818C0D, 0x8FB3BC3F, 0x86929416, 0x4B73783B, + 0x4C505C1C, 0x82A2A022, 0x81A1A021, 0x43636023, 0x03232023, 0x4D414C0D, + 0xC8C0C808, 0x8E929C1E, 0x8C909C1C, 0x0A32383A, 0x0C000C0C, 0x0E222C2E, + 0x8AB2B83A, 0x4E626C2E, 0x8F939C1F, 0x4A52581A, 0xC2F2F032, 0x82929012, + 0xC3F3F033, 0x49414809, 0x48707838, 0xCCC0CC0C, 0x05111415, 0xCBF3F83B, + 0x40707030, 0x45717435, 0x4F737C3F, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4D616C2D, 0xC6C2C406, 0x44707434, 0xC5D1D415, 0x84B0B434, + 0xCAE2E82A, 0x09010809, 0x46727436, 0x09111819, 0xCEF2FC3E, 0x40404000, + 0x02121012, 0xC0E0E020, 0x8DB1BC3D, 0x05010405, 0xCAF2F83A, 0x01010001, + 0xC0F0F030, 0x0A22282A, 0x4E525C1E, 0x89A1A829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8B93981B, 0x80B0B030, 0xC5E1E425, + 0x48404808, 0x49717839, 0x87939417, 0xCCF0FC3C, 0x0E121C1E, 0x82828002, + 0x01212021, 0x8C808C0C, 0x0B13181B, 0x4F535C1F, 0x47737437, 0x44505414, + 0x82B2B032, 0x0D111C1D, 0x05212425, 0x4F434C0F, 0x00000000, 0x46424406, + 0xCDE1EC2D, 0x48505818, 0x42525012, 0xCBE3E82B, 0x4E727C3E, 0xCAD2D81A, + 0xC9C1C809, 0xCDF1FC3D, 0x00303030, 0x85919415, 0x45616425, 0x0C303C3C, + 0x86B2B436, 0xC4E0E424, 0x8BB3B83B, 0x4C707C3C, 0x0E020C0E, 0x40505010, + 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xC7E3E427, 0x04202424, 0x84A0A424, 0xCBC3C80B, 0x43535013, + 0x0A02080A, 0x87838407, 0xC9D1D819, 0x4C404C0C, 0x83838003, 0x8F838C0F, + 0xCEC2CC0E, 0x0B33383B, 0x4A42480A, 0x87B3B437 }; + +} +/* +* Serpent +* (C) 1999-2007 Jack Lloyd +* +* The sbox expressions used here were discovered by Dag Arne Osvik and +* are described in his paper "Speeding Up Serpent". +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Serpent Encryption S-Box 1 +*/ +inline void SBoxE1(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T3 ^= T0; T4 = T1; T1 &= T3; T4 ^= T2; T1 ^= T0; T0 |= T3; T0 ^= T4; + T4 ^= T3; T3 ^= T2; T2 |= T1; T2 ^= T4; T4 = ~T4; T4 |= T1; T1 ^= T3; + T1 ^= T4; T3 |= T0; T1 ^= T3; T4 ^= T3; + B0 = T1; B1 = T4; B2 = T2; B3 = T0; + } + +/* +* Serpent Encryption S-Box 2 +*/ +inline void SBoxE2(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T0 = ~T0; T2 = ~T2; T4 = T0; T0 &= T1; T2 ^= T0; T0 |= T3; T3 ^= T2; + T1 ^= T0; T0 ^= T4; T4 |= T1; T1 ^= T3; T2 |= T0; T2 &= T4; T0 ^= T1; + T1 &= T2; T1 ^= T0; T0 &= T2; T0 ^= T4; + B0 = T2; B1 = T0; B2 = T3; B3 = T1; + } + +/* +* Serpent Encryption S-Box 3 +*/ +inline void SBoxE3(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T0; T0 &= T2; T0 ^= T3; T2 ^= T1; T2 ^= T0; T3 |= T4; T3 ^= T1; + T4 ^= T2; T1 = T3; T3 |= T4; T3 ^= T0; T0 &= T1; T4 ^= T0; T1 ^= T3; + T1 ^= T4; T4 = ~T4; + B0 = T2; B1 = T3; B2 = T1; B3 = T4; + } + +/* +* Serpent Encryption S-Box 4 +*/ +inline void SBoxE4(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T0; T0 |= T3; T3 ^= T1; T1 &= T4; T4 ^= T2; T2 ^= T3; T3 &= T0; + T4 |= T1; T3 ^= T4; T0 ^= T1; T4 &= T0; T1 ^= T3; T4 ^= T2; T1 |= T0; + T1 ^= T2; T0 ^= T3; T2 = T1; T1 |= T3; T1 ^= T0; + B0 = T1; B1 = T2; B2 = T3; B3 = T4; + } + +/* +* Serpent Encryption S-Box 5 +*/ +inline void SBoxE5(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T1 ^= T3; T3 = ~T3; T2 ^= T3; T3 ^= T0; T4 = T1; T1 &= T3; T1 ^= T2; + T4 ^= T3; T0 ^= T4; T2 &= T4; T2 ^= T0; T0 &= T1; T3 ^= T0; T4 |= T1; + T4 ^= T0; T0 |= T3; T0 ^= T2; T2 &= T3; T0 = ~T0; T4 ^= T2; + B0 = T1; B1 = T4; B2 = T0; B3 = T3; + } + +/* +* Serpent Encryption S-Box 6 +*/ +inline void SBoxE6(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T0 ^= T1; T1 ^= T3; T3 = ~T3; T4 = T1; T1 &= T0; T2 ^= T3; T1 ^= T2; + T2 |= T4; T4 ^= T3; T3 &= T1; T3 ^= T0; T4 ^= T1; T4 ^= T2; T2 ^= T0; + T0 &= T3; T2 = ~T2; T0 ^= T4; T4 |= T3; T2 ^= T4; + B0 = T1; B1 = T3; B2 = T0; B3 = T2; + } + +/* +* Serpent Encryption S-Box 7 +*/ +inline void SBoxE7(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T2 = ~T2; T4 = T3; T3 &= T0; T0 ^= T4; T3 ^= T2; T2 |= T4; T1 ^= T3; + T2 ^= T0; T0 |= T1; T2 ^= T1; T4 ^= T0; T0 |= T3; T0 ^= T2; T4 ^= T3; + T4 ^= T0; T3 = ~T3; T2 &= T4; T2 ^= T3; + B0 = T0; B1 = T1; B2 = T4; B3 = T2; + } + +/* +* Serpent Encryption S-Box 8 +*/ +inline void SBoxE8(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T1; T1 |= T2; T1 ^= T3; T4 ^= T2; T2 ^= T1; T3 |= T4; T3 &= T0; + T4 ^= T2; T3 ^= T1; T1 |= T4; T1 ^= T0; T0 |= T4; T0 ^= T2; T1 ^= T4; + T2 ^= T1; T1 &= T0; T1 ^= T4; T2 = ~T2; T2 |= T0; T4 ^= T2; + B0 = T4; B1 = T3; B2 = T1; B3 = T0; + } + +/* +* Serpent Decryption S-Box 1 +*/ +inline void SBoxD1(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T2 = ~T2; T4 = T1; T1 |= T0; T4 = ~T4; T1 ^= T2; T2 |= T4; T1 ^= T3; + T0 ^= T4; T2 ^= T0; T0 &= T3; T4 ^= T0; T0 |= T1; T0 ^= T2; T3 ^= T4; + T2 ^= T1; T3 ^= T0; T3 ^= T1; T2 &= T3; T4 ^= T2; + B0 = T0; B1 = T4; B2 = T1; B3 = T3; + } + +/* +* Serpent Decryption S-Box 2 +*/ +inline void SBoxD2(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T1; T1 ^= T3; T3 &= T1; T4 ^= T2; T3 ^= T0; T0 |= T1; T2 ^= T3; + T0 ^= T4; T0 |= T2; T1 ^= T3; T0 ^= T1; T1 |= T3; T1 ^= T0; T4 = ~T4; + T4 ^= T1; T1 |= T0; T1 ^= T0; T1 |= T4; T3 ^= T1; + B0 = T4; B1 = T0; B2 = T3; B3 = T2; + } + +/* +* Serpent Decryption S-Box 3 +*/ +inline void SBoxD3(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T2 ^= T3; T3 ^= T0; T4 = T3; T3 &= T2; T3 ^= T1; T1 |= T2; T1 ^= T4; + T4 &= T3; T2 ^= T3; T4 &= T0; T4 ^= T2; T2 &= T1; T2 |= T0; T3 = ~T3; + T2 ^= T3; T0 ^= T3; T0 &= T1; T3 ^= T4; T3 ^= T0; + B0 = T1; B1 = T4; B2 = T2; B3 = T3; + } + +/* +* Serpent Decryption S-Box 4 +*/ +inline void SBoxD4(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T2; T2 ^= T1; T0 ^= T2; T4 &= T2; T4 ^= T0; T0 &= T1; T1 ^= T3; + T3 |= T4; T2 ^= T3; T0 ^= T3; T1 ^= T4; T3 &= T2; T3 ^= T1; T1 ^= T0; + T1 |= T2; T0 ^= T3; T1 ^= T4; T0 ^= T1; + B0 = T2; B1 = T1; B2 = T3; B3 = T0; + } + +/* +* Serpent Decryption S-Box 5 +*/ +inline void SBoxD5(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T2; T2 &= T3; T2 ^= T1; T1 |= T3; T1 &= T0; T4 ^= T2; T4 ^= T1; + T1 &= T2; T0 = ~T0; T3 ^= T4; T1 ^= T3; T3 &= T0; T3 ^= T2; T0 ^= T1; + T2 &= T0; T3 ^= T0; T2 ^= T4; T2 |= T3; T3 ^= T0; T2 ^= T1; + B0 = T0; B1 = T3; B2 = T2; B3 = T4; + } + +/* +* Serpent Decryption S-Box 6 +*/ +inline void SBoxD6(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T1 = ~T1; T4 = T3; T2 ^= T1; T3 |= T0; T3 ^= T2; T2 |= T1; T2 &= T0; + T4 ^= T3; T2 ^= T4; T4 |= T0; T4 ^= T1; T1 &= T2; T1 ^= T3; T4 ^= T2; + T3 &= T4; T4 ^= T1; T3 ^= T4; T4 = ~T4; T3 ^= T0; + B0 = T1; B1 = T4; B2 = T3; B3 = T2; + } + +/* +* Serpent Decryption S-Box 7 +*/ +inline void SBoxD7(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T0 ^= T2; T4 = T2; T2 &= T0; T4 ^= T3; T2 = ~T2; T3 ^= T1; T2 ^= T3; + T4 |= T0; T0 ^= T2; T3 ^= T4; T4 ^= T1; T1 &= T3; T1 ^= T0; T0 ^= T3; + T0 |= T2; T3 ^= T1; T4 ^= T0; + B0 = T1; B1 = T2; B2 = T4; B3 = T3; + } + +/* +* Serpent Decryption S-Box 8 +*/ +inline void SBoxD8(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + u32bit T0 = B0, T1 = B1, T2 = B2, T3 = B3, T4; + T4 = T2; T2 ^= T0; T0 &= T3; T4 |= T3; T2 = ~T2; T3 ^= T1; T1 |= T0; + T0 ^= T2; T2 &= T4; T3 &= T4; T1 ^= T2; T2 ^= T0; T0 |= T2; T4 ^= T1; + T0 ^= T3; T3 ^= T4; T4 |= T0; T3 ^= T2; T4 ^= T2; + B0 = T3; B1 = T0; B2 = T1; B3 = T4; + } + +/* +* Serpent's Linear Transformation +*/ +inline void transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + B0 = rotate_left(B0, 13); B2 = rotate_left(B2, 3); + B1 ^= B0 ^ B2; B3 ^= B2 ^ (B0 << 3); + B1 = rotate_left(B1, 1); B3 = rotate_left(B3, 7); + B0 ^= B1 ^ B3; B2 ^= B3 ^ (B1 << 7); + B0 = rotate_left(B0, 5); B2 = rotate_left(B2, 22); + } + +/* +* Serpent's Inverse Linear Transformation +*/ +inline void i_transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) + { + B2 = rotate_right(B2, 22); B0 = rotate_right(B0, 5); + B2 ^= B3 ^ (B1 << 7); B0 ^= B1 ^ B3; + B3 = rotate_right(B3, 7); B1 = rotate_right(B1, 1); + B3 ^= B2 ^ (B0 << 3); B1 ^= B0 ^ B2; + B2 = rotate_right(B2, 3); B0 = rotate_right(B0, 13); + } + +} + +/* +* XOR a key block with a data block +*/ +#define key_xor(round, B0, B1, B2, B3) \ + B0 ^= round_key[4*round ]; \ + B1 ^= round_key[4*round+1]; \ + B2 ^= round_key[4*round+2]; \ + B3 ^= round_key[4*round+3]; + +/* +* Serpent Encryption +*/ +void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_le(in, 0); + u32bit B1 = load_le(in, 1); + u32bit B2 = load_le(in, 2); + u32bit B3 = load_le(in, 3); + + key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + store_le(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Serpent Decryption +*/ +void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0 = load_le(in, 0); + u32bit B1 = load_le(in, 1); + u32bit B2 = load_le(in, 2); + u32bit B3 = load_le(in, 3); + + key_xor(32,B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + store_le(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +#undef key_xor +#undef transform +#undef i_transform + +/* +* Serpent Key Schedule +*/ +void Serpent::key_schedule(const byte key[], size_t length) + { + const u32bit PHI = 0x9E3779B9; + + SecureVector W(140); + for(size_t i = 0; i != length / 4; ++i) + W[i] = load_le(key, i); + + W[length / 4] |= u32bit(1) << ((length%4)*8); + + for(size_t i = 8; i != 140; ++i) + { + u32bit wi = W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ u32bit(i-8); + W[i] = rotate_left(wi, 11); + } + + SBoxE4(W[ 8],W[ 9],W[ 10],W[ 11]); SBoxE3(W[ 12],W[ 13],W[ 14],W[ 15]); + SBoxE2(W[ 16],W[ 17],W[ 18],W[ 19]); SBoxE1(W[ 20],W[ 21],W[ 22],W[ 23]); + SBoxE8(W[ 24],W[ 25],W[ 26],W[ 27]); SBoxE7(W[ 28],W[ 29],W[ 30],W[ 31]); + SBoxE6(W[ 32],W[ 33],W[ 34],W[ 35]); SBoxE5(W[ 36],W[ 37],W[ 38],W[ 39]); + SBoxE4(W[ 40],W[ 41],W[ 42],W[ 43]); SBoxE3(W[ 44],W[ 45],W[ 46],W[ 47]); + SBoxE2(W[ 48],W[ 49],W[ 50],W[ 51]); SBoxE1(W[ 52],W[ 53],W[ 54],W[ 55]); + SBoxE8(W[ 56],W[ 57],W[ 58],W[ 59]); SBoxE7(W[ 60],W[ 61],W[ 62],W[ 63]); + SBoxE6(W[ 64],W[ 65],W[ 66],W[ 67]); SBoxE5(W[ 68],W[ 69],W[ 70],W[ 71]); + SBoxE4(W[ 72],W[ 73],W[ 74],W[ 75]); SBoxE3(W[ 76],W[ 77],W[ 78],W[ 79]); + SBoxE2(W[ 80],W[ 81],W[ 82],W[ 83]); SBoxE1(W[ 84],W[ 85],W[ 86],W[ 87]); + SBoxE8(W[ 88],W[ 89],W[ 90],W[ 91]); SBoxE7(W[ 92],W[ 93],W[ 94],W[ 95]); + SBoxE6(W[ 96],W[ 97],W[ 98],W[ 99]); SBoxE5(W[100],W[101],W[102],W[103]); + SBoxE4(W[104],W[105],W[106],W[107]); SBoxE3(W[108],W[109],W[110],W[111]); + SBoxE2(W[112],W[113],W[114],W[115]); SBoxE1(W[116],W[117],W[118],W[119]); + SBoxE8(W[120],W[121],W[122],W[123]); SBoxE7(W[124],W[125],W[126],W[127]); + SBoxE6(W[128],W[129],W[130],W[131]); SBoxE5(W[132],W[133],W[134],W[135]); + SBoxE4(W[136],W[137],W[138],W[139]); + round_key.copy(&W[8], 132); + } + +} +/* +* Serpent (SIMD) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +#define SBoxE1(B0, B1, B2, B3) \ + do { \ + B3 ^= B0; \ + SIMD_32 B4 = B1; \ + B1 &= B3; \ + B4 ^= B2; \ + B1 ^= B0; \ + B0 |= B3; \ + B0 ^= B4; \ + B4 ^= B3; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 ^= B4; \ + B4 = ~B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B1 ^= B4; \ + B3 |= B0; \ + B1 ^= B3; \ + B4 ^= B3; \ + B3 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE2(B0, B1, B2, B3) \ + do { \ + B0 = ~B0; \ + B2 = ~B2; \ + SIMD_32 B4 = B0; \ + B0 &= B1; \ + B2 ^= B0; \ + B0 |= B3; \ + B3 ^= B2; \ + B1 ^= B0; \ + B0 ^= B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B2 |= B0; \ + B2 &= B4; \ + B0 ^= B1; \ + B1 &= B2; \ + B1 ^= B0; \ + B0 &= B2; \ + B4 ^= B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE3(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B0; \ + B0 &= B2; \ + B0 ^= B3; \ + B2 ^= B1; \ + B2 ^= B0; \ + B3 |= B4; \ + B3 ^= B1; \ + B4 ^= B2; \ + B1 = B3; \ + B3 |= B4; \ + B3 ^= B0; \ + B0 &= B1; \ + B4 ^= B0; \ + B1 ^= B3; \ + B1 ^= B4; \ + B0 = B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = ~B4; \ + } while(0); + +#define SBoxE4(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B0; \ + B0 |= B3; \ + B3 ^= B1; \ + B1 &= B4; \ + B4 ^= B2; \ + B2 ^= B3; \ + B3 &= B0; \ + B4 |= B1; \ + B3 ^= B4; \ + B0 ^= B1; \ + B4 &= B0; \ + B1 ^= B3; \ + B4 ^= B2; \ + B1 |= B0; \ + B1 ^= B2; \ + B0 ^= B3; \ + B2 = B1; \ + B1 |= B3; \ + B0 ^= B1; \ + B1 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE5(B0, B1, B2, B3) \ + do { \ + B1 ^= B3; \ + B3 = ~B3; \ + B2 ^= B3; \ + B3 ^= B0; \ + SIMD_32 B4 = B1; \ + B1 &= B3; \ + B1 ^= B2; \ + B4 ^= B3; \ + B0 ^= B4; \ + B2 &= B4; \ + B2 ^= B0; \ + B0 &= B1; \ + B3 ^= B0; \ + B4 |= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B2 &= B3; \ + B0 = ~B0; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE6(B0, B1, B2, B3) \ + do { \ + B0 ^= B1; \ + B1 ^= B3; \ + B3 = ~B3; \ + SIMD_32 B4 = B1; \ + B1 &= B0; \ + B2 ^= B3; \ + B1 ^= B2; \ + B2 |= B4; \ + B4 ^= B3; \ + B3 &= B1; \ + B3 ^= B0; \ + B4 ^= B1; \ + B4 ^= B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B2 = ~B2; \ + B0 ^= B4; \ + B4 |= B3; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE7(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + SIMD_32 B4 = B3; \ + B3 &= B0; \ + B0 ^= B4; \ + B3 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B2 ^= B0; \ + B0 |= B1; \ + B2 ^= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B4 ^= B3; \ + B4 ^= B0; \ + B3 = ~B3; \ + B2 &= B4; \ + B3 ^= B2; \ + B2 = B4; \ + } while(0); + +#define SBoxE8(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B1; \ + B1 |= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B2 ^= B1; \ + B3 |= B4; \ + B3 &= B0; \ + B4 ^= B2; \ + B3 ^= B1; \ + B1 |= B4; \ + B1 ^= B0; \ + B0 |= B4; \ + B0 ^= B2; \ + B1 ^= B4; \ + B2 ^= B1; \ + B1 &= B0; \ + B1 ^= B4; \ + B2 = ~B2; \ + B2 |= B0; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = B0; \ + B0 = B4; \ + } while(0); + +#define SBoxD1(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + SIMD_32 B4 = B1; \ + B1 |= B0; \ + B4 = ~B4; \ + B1 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B0 ^= B4; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 ^= B0; \ + B0 |= B1; \ + B0 ^= B2; \ + B3 ^= B4; \ + B2 ^= B1; \ + B3 ^= B0; \ + B3 ^= B1; \ + B2 &= B3; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD2(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B1; \ + B1 ^= B3; \ + B3 &= B1; \ + B4 ^= B2; \ + B3 ^= B0; \ + B0 |= B1; \ + B2 ^= B3; \ + B0 ^= B4; \ + B0 |= B2; \ + B1 ^= B3; \ + B0 ^= B1; \ + B1 |= B3; \ + B1 ^= B0; \ + B4 = ~B4; \ + B4 ^= B1; \ + B1 |= B0; \ + B1 ^= B0; \ + B1 |= B4; \ + B3 ^= B1; \ + B1 = B0; \ + B0 = B4; \ + B4 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD3(B0, B1, B2, B3) \ + do { \ + B2 ^= B3; \ + B3 ^= B0; \ + SIMD_32 B4 = B3; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 |= B2; \ + B1 ^= B4; \ + B4 &= B3; \ + B2 ^= B3; \ + B4 &= B0; \ + B4 ^= B2; \ + B2 &= B1; \ + B2 |= B0; \ + B3 = ~B3; \ + B2 ^= B3; \ + B0 ^= B3; \ + B0 &= B1; \ + B3 ^= B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD4(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 ^= B1; \ + B0 ^= B2; \ + B4 &= B2; \ + B4 ^= B0; \ + B0 &= B1; \ + B1 ^= B3; \ + B3 |= B4; \ + B2 ^= B3; \ + B0 ^= B3; \ + B1 ^= B4; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 ^= B0; \ + B1 |= B2; \ + B0 ^= B3; \ + B1 ^= B4; \ + B0 ^= B1; \ + B4 = B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD5(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 &= B3; \ + B2 ^= B1; \ + B1 |= B3; \ + B1 &= B0; \ + B4 ^= B2; \ + B4 ^= B1; \ + B1 &= B2; \ + B0 = ~B0; \ + B3 ^= B4; \ + B1 ^= B3; \ + B3 &= B0; \ + B3 ^= B2; \ + B0 ^= B1; \ + B2 &= B0; \ + B3 ^= B0; \ + B2 ^= B4; \ + B2 |= B3; \ + B3 ^= B0; \ + B2 ^= B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD6(B0, B1, B2, B3) \ + do { \ + B1 = ~B1; \ + SIMD_32 B4 = B3; \ + B2 ^= B1; \ + B3 |= B0; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 ^= B4; \ + B4 |= B0; \ + B4 ^= B1; \ + B1 &= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B3 &= B4; \ + B4 ^= B1; \ + B3 ^= B4; \ + B4 = ~B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + B4 = B3; \ + B3 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD7(B0, B1, B2, B3) \ + do { \ + B0 ^= B2; \ + SIMD_32 B4 = B2; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B2 ^= B3; \ + B4 |= B0; \ + B0 ^= B2; \ + B3 ^= B4; \ + B4 ^= B1; \ + B1 &= B3; \ + B1 ^= B0; \ + B0 ^= B3; \ + B0 |= B2; \ + B3 ^= B1; \ + B4 ^= B0; \ + B0 = B1; \ + B1 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD8(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 |= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B1 |= B0; \ + B0 ^= B2; \ + B2 &= B4; \ + B3 &= B4; \ + B1 ^= B2; \ + B2 ^= B0; \ + B0 |= B2; \ + B4 ^= B1; \ + B0 ^= B3; \ + B3 ^= B4; \ + B4 |= B0; \ + B3 ^= B2; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B0; \ + B0 = B3; \ + B3 = B4; \ + } while(0); + +#define key_xor(round, B0, B1, B2, B3) \ + do { \ + B0 ^= SIMD_32(keys[4*round ]); \ + B1 ^= SIMD_32(keys[4*round+1]); \ + B2 ^= SIMD_32(keys[4*round+2]); \ + B3 ^= SIMD_32(keys[4*round+3]); \ + } while(0); + +/* +* Serpent's linear transformations +*/ +#define transform(B0, B1, B2, B3) \ + do { \ + B0.rotate_left(13); \ + B2.rotate_left(3); \ + B1 ^= B0 ^ B2; \ + B3 ^= B2 ^ (B0 << 3); \ + B1.rotate_left(1); \ + B3.rotate_left(7); \ + B0 ^= B1 ^ B3; \ + B2 ^= B3 ^ (B1 << 7); \ + B0.rotate_left(5); \ + B2.rotate_left(22); \ + } while(0); + +#define i_transform(B0, B1, B2, B3) \ + do { \ + B2.rotate_right(22); \ + B0.rotate_right(5); \ + B2 ^= B3 ^ (B1 << 7); \ + B0 ^= B1 ^ B3; \ + B3.rotate_right(7); \ + B1.rotate_right(1); \ + B3 ^= B2 ^ (B0 << 3); \ + B1 ^= B0 ^ B2; \ + B2.rotate_right(3); \ + B0.rotate_right(13); \ + } while(0); + +/* +* SIMD Serpent Encryption of 4 blocks in parallel +*/ +void serpent_encrypt_4(const byte in[64], + byte out[64], + const u32bit keys[132]) + { + SIMD_32 B0 = SIMD_32::load_le(in); + SIMD_32 B1 = SIMD_32::load_le(in + 16); + SIMD_32 B2 = SIMD_32::load_le(in + 32); + SIMD_32 B3 = SIMD_32::load_le(in + 48); + + SIMD_32::transpose(B0, B1, B2, B3); + + key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + SIMD_32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +/* +* SIMD Serpent Decryption of 4 blocks in parallel +*/ +void serpent_decrypt_4(const byte in[64], + byte out[64], + const u32bit keys[132]) + { + SIMD_32 B0 = SIMD_32::load_le(in); + SIMD_32 B1 = SIMD_32::load_le(in + 16); + SIMD_32 B2 = SIMD_32::load_le(in + 32); + SIMD_32 B3 = SIMD_32::load_le(in + 48); + + SIMD_32::transpose(B0, B1, B2, B3); + + key_xor(32,B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + SIMD_32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +} + +#undef key_xor +#undef transform +#undef i_transform + +#undef SBoxE1 +#undef SBoxE2 +#undef SBoxE3 +#undef SBoxE4 +#undef SBoxE5 +#undef SBoxE6 +#undef SBoxE7 +#undef SBoxE8 + +#undef SBoxD1 +#undef SBoxD2 +#undef SBoxD3 +#undef SBoxD4 +#undef SBoxD5 +#undef SBoxD6 +#undef SBoxD7 +#undef SBoxD8 + +/* +* Serpent Encryption +*/ +void Serpent_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_round_keys()[0]); + + while(blocks >= 4) + { + serpent_encrypt_4(in, out, KS); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + if(blocks) + Serpent::encrypt_n(in, out, blocks); + } + +/* +* Serpent Decryption +*/ +void Serpent_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_round_keys()[0]); + + while(blocks >= 4) + { + serpent_decrypt_4(in, out, KS); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + if(blocks) + Serpent::decrypt_n(in, out, blocks); + } + +} +/* +* Skipjack +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Skipjack Stepping Rule 'A' +*/ +void step_A(u16bit& W1, u16bit& W4, size_t round, const byte FTAB[]) + { + byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3; + + G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1; + G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2; + G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3; + G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1; + + W1 = make_u16bit(G2, G3); + W4 ^= W1 ^ round; + } + +/* +* Skipjack Stepping Rule 'B' +*/ +void step_B(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[]) + { + W2 ^= W1 ^ round; + byte G1 = get_byte(0, W1), G2 = get_byte(1, W1), G3; + G3 = FTAB[((4*round-4)%10)*256 + G2] ^ G1; + G1 = FTAB[((4*round-3)%10)*256 + G3] ^ G2; + G2 = FTAB[((4*round-2)%10)*256 + G1] ^ G3; + G3 = FTAB[((4*round-1)%10)*256 + G2] ^ G1; + W1 = make_u16bit(G2, G3); + } + +/* +* Skipjack Invserse Stepping Rule 'A' +*/ +void step_Ai(u16bit& W1, u16bit& W2, size_t round, const byte FTAB[]) + { + W1 ^= W2 ^ round; + byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3; + G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1; + G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2; + G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3; + G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1; + W2 = make_u16bit(G3, G2); + } + +/* +* Skipjack Invserse Stepping Rule 'B' +*/ +void step_Bi(u16bit& W2, u16bit& W3, size_t round, const byte FTAB[]) + { + byte G1 = get_byte(1, W2), G2 = get_byte(0, W2), G3; + G3 = FTAB[((4 * round - 1) % 10)*256 + G2] ^ G1; + G1 = FTAB[((4 * round - 2) % 10)*256 + G3] ^ G2; + G2 = FTAB[((4 * round - 3) % 10)*256 + G1] ^ G3; + G3 = FTAB[((4 * round - 4) % 10)*256 + G2] ^ G1; + W2 = make_u16bit(G3, G2); + W3 ^= W2 ^ round; + } + +} + +/* +* Skipjack Encryption +*/ +void Skipjack::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const byte* ftab = &FTAB[0]; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit W1 = load_le(in, 3); + u16bit W2 = load_le(in, 2); + u16bit W3 = load_le(in, 1); + u16bit W4 = load_le(in, 0); + + step_A(W1, W4, 1, ftab); step_A(W4, W3, 2, ftab); + step_A(W3, W2, 3, ftab); step_A(W2, W1, 4, ftab); + step_A(W1, W4, 5, ftab); step_A(W4, W3, 6, ftab); + step_A(W3, W2, 7, ftab); step_A(W2, W1, 8, ftab); + + step_B(W1, W2, 9, ftab); step_B(W4, W1, 10, ftab); + step_B(W3, W4, 11, ftab); step_B(W2, W3, 12, ftab); + step_B(W1, W2, 13, ftab); step_B(W4, W1, 14, ftab); + step_B(W3, W4, 15, ftab); step_B(W2, W3, 16, ftab); + + step_A(W1, W4, 17, ftab); step_A(W4, W3, 18, ftab); + step_A(W3, W2, 19, ftab); step_A(W2, W1, 20, ftab); + step_A(W1, W4, 21, ftab); step_A(W4, W3, 22, ftab); + step_A(W3, W2, 23, ftab); step_A(W2, W1, 24, ftab); + + step_B(W1, W2, 25, ftab); step_B(W4, W1, 26, ftab); + step_B(W3, W4, 27, ftab); step_B(W2, W3, 28, ftab); + step_B(W1, W2, 29, ftab); step_B(W4, W1, 30, ftab); + step_B(W3, W4, 31, ftab); step_B(W2, W3, 32, ftab); + + store_le(out, W4, W3, W2, W1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Skipjack Decryption +*/ +void Skipjack::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const byte* ftab = &FTAB[0]; + + for(size_t i = 0; i != blocks; ++i) + { + u16bit W1 = load_le(in, 3); + u16bit W2 = load_le(in, 2); + u16bit W3 = load_le(in, 1); + u16bit W4 = load_le(in, 0); + + step_Bi(W2, W3, 32, ftab); step_Bi(W3, W4, 31, ftab); + step_Bi(W4, W1, 30, ftab); step_Bi(W1, W2, 29, ftab); + step_Bi(W2, W3, 28, ftab); step_Bi(W3, W4, 27, ftab); + step_Bi(W4, W1, 26, ftab); step_Bi(W1, W2, 25, ftab); + + step_Ai(W1, W2, 24, ftab); step_Ai(W2, W3, 23, ftab); + step_Ai(W3, W4, 22, ftab); step_Ai(W4, W1, 21, ftab); + step_Ai(W1, W2, 20, ftab); step_Ai(W2, W3, 19, ftab); + step_Ai(W3, W4, 18, ftab); step_Ai(W4, W1, 17, ftab); + + step_Bi(W2, W3, 16, ftab); step_Bi(W3, W4, 15, ftab); + step_Bi(W4, W1, 14, ftab); step_Bi(W1, W2, 13, ftab); + step_Bi(W2, W3, 12, ftab); step_Bi(W3, W4, 11, ftab); + step_Bi(W4, W1, 10, ftab); step_Bi(W1, W2, 9, ftab); + + step_Ai(W1, W2, 8, ftab); step_Ai(W2, W3, 7, ftab); + step_Ai(W3, W4, 6, ftab); step_Ai(W4, W1, 5, ftab); + step_Ai(W1, W2, 4, ftab); step_Ai(W2, W3, 3, ftab); + step_Ai(W3, W4, 2, ftab); step_Ai(W4, W1, 1, ftab); + + store_le(out, W4, W3, W2, W1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Skipjack Key Schedule +*/ +void Skipjack::key_schedule(const byte key[], size_t) + { + static const byte F[256] = { + 0xA3, 0xD7, 0x09, 0x83, 0xF8, 0x48, 0xF6, 0xF4, 0xB3, 0x21, 0x15, 0x78, + 0x99, 0xB1, 0xAF, 0xF9, 0xE7, 0x2D, 0x4D, 0x8A, 0xCE, 0x4C, 0xCA, 0x2E, + 0x52, 0x95, 0xD9, 0x1E, 0x4E, 0x38, 0x44, 0x28, 0x0A, 0xDF, 0x02, 0xA0, + 0x17, 0xF1, 0x60, 0x68, 0x12, 0xB7, 0x7A, 0xC3, 0xE9, 0xFA, 0x3D, 0x53, + 0x96, 0x84, 0x6B, 0xBA, 0xF2, 0x63, 0x9A, 0x19, 0x7C, 0xAE, 0xE5, 0xF5, + 0xF7, 0x16, 0x6A, 0xA2, 0x39, 0xB6, 0x7B, 0x0F, 0xC1, 0x93, 0x81, 0x1B, + 0xEE, 0xB4, 0x1A, 0xEA, 0xD0, 0x91, 0x2F, 0xB8, 0x55, 0xB9, 0xDA, 0x85, + 0x3F, 0x41, 0xBF, 0xE0, 0x5A, 0x58, 0x80, 0x5F, 0x66, 0x0B, 0xD8, 0x90, + 0x35, 0xD5, 0xC0, 0xA7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, + 0x6D, 0x98, 0x9B, 0x76, 0x97, 0xFC, 0xB2, 0xC2, 0xB0, 0xFE, 0xDB, 0x20, + 0xE1, 0xEB, 0xD6, 0xE4, 0xDD, 0x47, 0x4A, 0x1D, 0x42, 0xED, 0x9E, 0x6E, + 0x49, 0x3C, 0xCD, 0x43, 0x27, 0xD2, 0x07, 0xD4, 0xDE, 0xC7, 0x67, 0x18, + 0x89, 0xCB, 0x30, 0x1F, 0x8D, 0xC6, 0x8F, 0xAA, 0xC8, 0x74, 0xDC, 0xC9, + 0x5D, 0x5C, 0x31, 0xA4, 0x70, 0x88, 0x61, 0x2C, 0x9F, 0x0D, 0x2B, 0x87, + 0x50, 0x82, 0x54, 0x64, 0x26, 0x7D, 0x03, 0x40, 0x34, 0x4B, 0x1C, 0x73, + 0xD1, 0xC4, 0xFD, 0x3B, 0xCC, 0xFB, 0x7F, 0xAB, 0xE6, 0x3E, 0x5B, 0xA5, + 0xAD, 0x04, 0x23, 0x9C, 0x14, 0x51, 0x22, 0xF0, 0x29, 0x79, 0x71, 0x7E, + 0xFF, 0x8C, 0x0E, 0xE2, 0x0C, 0xEF, 0xBC, 0x72, 0x75, 0x6F, 0x37, 0xA1, + 0xEC, 0xD3, 0x8E, 0x62, 0x8B, 0x86, 0x10, 0xE8, 0x08, 0x77, 0x11, 0xBE, + 0x92, 0x4F, 0x24, 0xC5, 0x32, 0x36, 0x9D, 0xCF, 0xF3, 0xA6, 0xBB, 0xAC, + 0x5E, 0x6C, 0xA9, 0x13, 0x57, 0x25, 0xB5, 0xE3, 0xBD, 0xA8, 0x3A, 0x01, + 0x05, 0x59, 0x2A, 0x46 }; + + for(size_t i = 0; i != 10; ++i) + for(size_t j = 0; j != 256; ++j) + FTAB[256*i+j] = F[j ^ key[9-i]]; + } + +/* +* Clear memory of sensitive data +*/ +void Skipjack::clear() + { + zeroise(FTAB); + } + +} +/* +* S-Box and Diffusion Tables for Square +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const byte Square::SE[256] = { +0xB1, 0xCE, 0xC3, 0x95, 0x5A, 0xAD, 0xE7, 0x02, 0x4D, 0x44, 0xFB, 0x91, 0x0C, +0x87, 0xA1, 0x50, 0xCB, 0x67, 0x54, 0xDD, 0x46, 0x8F, 0xE1, 0x4E, 0xF0, 0xFD, +0xFC, 0xEB, 0xF9, 0xC4, 0x1A, 0x6E, 0x5E, 0xF5, 0xCC, 0x8D, 0x1C, 0x56, 0x43, +0xFE, 0x07, 0x61, 0xF8, 0x75, 0x59, 0xFF, 0x03, 0x22, 0x8A, 0xD1, 0x13, 0xEE, +0x88, 0x00, 0x0E, 0x34, 0x15, 0x80, 0x94, 0xE3, 0xED, 0xB5, 0x53, 0x23, 0x4B, +0x47, 0x17, 0xA7, 0x90, 0x35, 0xAB, 0xD8, 0xB8, 0xDF, 0x4F, 0x57, 0x9A, 0x92, +0xDB, 0x1B, 0x3C, 0xC8, 0x99, 0x04, 0x8E, 0xE0, 0xD7, 0x7D, 0x85, 0xBB, 0x40, +0x2C, 0x3A, 0x45, 0xF1, 0x42, 0x65, 0x20, 0x41, 0x18, 0x72, 0x25, 0x93, 0x70, +0x36, 0x05, 0xF2, 0x0B, 0xA3, 0x79, 0xEC, 0x08, 0x27, 0x31, 0x32, 0xB6, 0x7C, +0xB0, 0x0A, 0x73, 0x5B, 0x7B, 0xB7, 0x81, 0xD2, 0x0D, 0x6A, 0x26, 0x9E, 0x58, +0x9C, 0x83, 0x74, 0xB3, 0xAC, 0x30, 0x7A, 0x69, 0x77, 0x0F, 0xAE, 0x21, 0xDE, +0xD0, 0x2E, 0x97, 0x10, 0xA4, 0x98, 0xA8, 0xD4, 0x68, 0x2D, 0x62, 0x29, 0x6D, +0x16, 0x49, 0x76, 0xC7, 0xE8, 0xC1, 0x96, 0x37, 0xE5, 0xCA, 0xF4, 0xE9, 0x63, +0x12, 0xC2, 0xA6, 0x14, 0xBC, 0xD3, 0x28, 0xAF, 0x2F, 0xE6, 0x24, 0x52, 0xC6, +0xA0, 0x09, 0xBD, 0x8C, 0xCF, 0x5D, 0x11, 0x5F, 0x01, 0xC5, 0x9F, 0x3D, 0xA2, +0x9B, 0xC9, 0x3B, 0xBE, 0x51, 0x19, 0x1F, 0x3F, 0x5C, 0xB2, 0xEF, 0x4A, 0xCD, +0xBF, 0xBA, 0x6F, 0x64, 0xD9, 0xF3, 0x3E, 0xB4, 0xAA, 0xDC, 0xD5, 0x06, 0xC0, +0x7E, 0xF6, 0x66, 0x6C, 0x84, 0x71, 0x38, 0xB9, 0x1D, 0x7F, 0x9D, 0x48, 0x8B, +0x2A, 0xDA, 0xA5, 0x33, 0x82, 0x39, 0xD6, 0x78, 0x86, 0xFA, 0xE4, 0x2B, 0xA9, +0x1E, 0x89, 0x60, 0x6B, 0xEA, 0x55, 0x4C, 0xF7, 0xE2 }; + +const byte Square::SD[256] = { +0x35, 0xBE, 0x07, 0x2E, 0x53, 0x69, 0xDB, 0x28, 0x6F, 0xB7, 0x76, 0x6B, 0x0C, +0x7D, 0x36, 0x8B, 0x92, 0xBC, 0xA9, 0x32, 0xAC, 0x38, 0x9C, 0x42, 0x63, 0xC8, +0x1E, 0x4F, 0x24, 0xE5, 0xF7, 0xC9, 0x61, 0x8D, 0x2F, 0x3F, 0xB3, 0x65, 0x7F, +0x70, 0xAF, 0x9A, 0xEA, 0xF5, 0x5B, 0x98, 0x90, 0xB1, 0x87, 0x71, 0x72, 0xED, +0x37, 0x45, 0x68, 0xA3, 0xE3, 0xEF, 0x5C, 0xC5, 0x50, 0xC1, 0xD6, 0xCA, 0x5A, +0x62, 0x5F, 0x26, 0x09, 0x5D, 0x14, 0x41, 0xE8, 0x9D, 0xCE, 0x40, 0xFD, 0x08, +0x17, 0x4A, 0x0F, 0xC7, 0xB4, 0x3E, 0x12, 0xFC, 0x25, 0x4B, 0x81, 0x2C, 0x04, +0x78, 0xCB, 0xBB, 0x20, 0xBD, 0xF9, 0x29, 0x99, 0xA8, 0xD3, 0x60, 0xDF, 0x11, +0x97, 0x89, 0x7E, 0xFA, 0xE0, 0x9B, 0x1F, 0xD2, 0x67, 0xE2, 0x64, 0x77, 0x84, +0x2B, 0x9E, 0x8A, 0xF1, 0x6D, 0x88, 0x79, 0x74, 0x57, 0xDD, 0xE6, 0x39, 0x7B, +0xEE, 0x83, 0xE1, 0x58, 0xF2, 0x0D, 0x34, 0xF8, 0x30, 0xE9, 0xB9, 0x23, 0x54, +0x15, 0x44, 0x0B, 0x4D, 0x66, 0x3A, 0x03, 0xA2, 0x91, 0x94, 0x52, 0x4C, 0xC3, +0x82, 0xE7, 0x80, 0xC0, 0xB6, 0x0E, 0xC2, 0x6C, 0x93, 0xEC, 0xAB, 0x43, 0x95, +0xF6, 0xD8, 0x46, 0x86, 0x05, 0x8C, 0xB0, 0x75, 0x00, 0xCC, 0x85, 0xD7, 0x3D, +0x73, 0x7A, 0x48, 0xE4, 0xD1, 0x59, 0xAD, 0xB8, 0xC6, 0xD0, 0xDC, 0xA1, 0xAA, +0x02, 0x1D, 0xBF, 0xB5, 0x9F, 0x51, 0xC4, 0xA5, 0x10, 0x22, 0xCF, 0x01, 0xBA, +0x8F, 0x31, 0x7C, 0xAE, 0x96, 0xDA, 0xF0, 0x56, 0x47, 0xD4, 0xEB, 0x4E, 0xD9, +0x13, 0x8E, 0x49, 0x55, 0x16, 0xFF, 0x3B, 0xF4, 0xA4, 0xB2, 0x06, 0xA0, 0xA7, +0xFB, 0x1B, 0x6E, 0x3C, 0x33, 0xCD, 0x18, 0x5E, 0x6A, 0xD5, 0xA6, 0x21, 0xDE, +0xFE, 0x2A, 0x1C, 0xF3, 0x0A, 0x1A, 0x19, 0x27, 0x2D }; + +const byte Square::Log[256] = { +0x00, 0x00, 0x01, 0x86, 0x02, 0x0D, 0x87, 0x4C, 0x03, 0xD2, 0x0E, 0xAE, 0x88, +0x22, 0x4D, 0x93, 0x04, 0x1A, 0xD3, 0xCB, 0x0F, 0x98, 0xAF, 0xA8, 0x89, 0xF0, +0x23, 0x59, 0x4E, 0x35, 0x94, 0x09, 0x05, 0x8F, 0x1B, 0x6E, 0xD4, 0x39, 0xCC, +0xBB, 0x10, 0x68, 0x99, 0x77, 0xB0, 0xDF, 0xA9, 0x72, 0x8A, 0xFA, 0xF1, 0xA0, +0x24, 0x52, 0x5A, 0x60, 0x4F, 0x2F, 0x36, 0xDC, 0x95, 0x32, 0x0A, 0x1F, 0x06, +0xA5, 0x90, 0x49, 0x1C, 0x5D, 0x6F, 0xB8, 0xD5, 0xC1, 0x3A, 0xB5, 0xCD, 0x63, +0xBC, 0x3D, 0x11, 0x44, 0x69, 0x81, 0x9A, 0x27, 0x78, 0xC4, 0xB1, 0xE6, 0xE0, +0xEA, 0xAA, 0x55, 0x73, 0xD8, 0x8B, 0xF6, 0xFB, 0x16, 0xF2, 0xF4, 0xA1, 0x40, +0x25, 0x42, 0x53, 0xE4, 0x5B, 0xA3, 0x61, 0xBF, 0x50, 0xF8, 0x30, 0x2D, 0x37, +0x8D, 0xDD, 0x66, 0x96, 0x18, 0x33, 0xEE, 0x0B, 0xFD, 0x20, 0xD0, 0x07, 0x57, +0xA6, 0xC9, 0x91, 0xAC, 0x4A, 0x84, 0x1D, 0xDA, 0x5E, 0x9E, 0x70, 0x75, 0xB9, +0x6C, 0xD6, 0xE8, 0xC2, 0x7F, 0x3B, 0xB3, 0xB6, 0x47, 0xCE, 0xEC, 0x64, 0x2B, +0xBD, 0xE2, 0x3E, 0x14, 0x12, 0x29, 0x45, 0x7D, 0x6A, 0x9C, 0x82, 0xC7, 0x9B, +0xC6, 0x28, 0x7C, 0x79, 0x7A, 0xC5, 0x7B, 0xB2, 0x46, 0xE7, 0x7E, 0xE1, 0x13, +0xEB, 0x2A, 0xAB, 0x83, 0x56, 0xC8, 0x74, 0x6B, 0xD9, 0x9D, 0x8C, 0x65, 0xF7, +0x2C, 0xFC, 0xCF, 0x17, 0xED, 0xF3, 0x3F, 0xF5, 0x15, 0xA2, 0xBE, 0x41, 0xE3, +0x26, 0xC3, 0x43, 0x80, 0x54, 0xD7, 0xE5, 0xE9, 0x5C, 0xB7, 0xA4, 0x48, 0x62, +0x3C, 0xC0, 0xB4, 0x51, 0x5F, 0xF9, 0x9F, 0x31, 0x1E, 0x2E, 0xDB, 0x38, 0xBA, +0x8E, 0x6D, 0xDE, 0x71, 0x67, 0x76, 0x97, 0xA7, 0x19, 0xCA, 0x34, 0x08, 0xEF, +0x58, 0x0C, 0x4B, 0xFE, 0x85, 0x21, 0x92, 0xD1, 0xAD }; + +const byte Square::ALog[255] = { +0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF5, 0x1F, 0x3E, 0x7C, 0xF8, +0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0xB5, 0x9F, 0xCB, 0x63, 0xC6, 0x79, 0xF2, +0x11, 0x22, 0x44, 0x88, 0xE5, 0x3F, 0x7E, 0xFC, 0x0D, 0x1A, 0x34, 0x68, 0xD0, +0x55, 0xAA, 0xA1, 0xB7, 0x9B, 0xC3, 0x73, 0xE6, 0x39, 0x72, 0xE4, 0x3D, 0x7A, +0xF4, 0x1D, 0x3A, 0x74, 0xE8, 0x25, 0x4A, 0x94, 0xDD, 0x4F, 0x9E, 0xC9, 0x67, +0xCE, 0x69, 0xD2, 0x51, 0xA2, 0xB1, 0x97, 0xDB, 0x43, 0x86, 0xF9, 0x07, 0x0E, +0x1C, 0x38, 0x70, 0xE0, 0x35, 0x6A, 0xD4, 0x5D, 0xBA, 0x81, 0xF7, 0x1B, 0x36, +0x6C, 0xD8, 0x45, 0x8A, 0xE1, 0x37, 0x6E, 0xDC, 0x4D, 0x9A, 0xC1, 0x77, 0xEE, +0x29, 0x52, 0xA4, 0xBD, 0x8F, 0xEB, 0x23, 0x46, 0x8C, 0xED, 0x2F, 0x5E, 0xBC, +0x8D, 0xEF, 0x2B, 0x56, 0xAC, 0xAD, 0xAF, 0xAB, 0xA3, 0xB3, 0x93, 0xD3, 0x53, +0xA6, 0xB9, 0x87, 0xFB, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x75, 0xEA, +0x21, 0x42, 0x84, 0xFD, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x15, 0x2A, 0x54, 0xA8, +0xA5, 0xBF, 0x8B, 0xE3, 0x33, 0x66, 0xCC, 0x6D, 0xDA, 0x41, 0x82, 0xF1, 0x17, +0x2E, 0x5C, 0xB8, 0x85, 0xFF, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x95, 0xDF, 0x4B, +0x96, 0xD9, 0x47, 0x8E, 0xE9, 0x27, 0x4E, 0x9C, 0xCD, 0x6F, 0xDE, 0x49, 0x92, +0xD1, 0x57, 0xAE, 0xA9, 0xA7, 0xBB, 0x83, 0xF3, 0x13, 0x26, 0x4C, 0x98, 0xC5, +0x7F, 0xFE, 0x09, 0x12, 0x24, 0x48, 0x90, 0xD5, 0x5F, 0xBE, 0x89, 0xE7, 0x3B, +0x76, 0xEC, 0x2D, 0x5A, 0xB4, 0x9D, 0xCF, 0x6B, 0xD6, 0x59, 0xB2, 0x91, 0xD7, +0x5B, 0xB6, 0x99, 0xC7, 0x7B, 0xF6, 0x19, 0x32, 0x64, 0xC8, 0x65, 0xCA, 0x61, +0xC2, 0x71, 0xE2, 0x31, 0x62, 0xC4, 0x7D, 0xFA }; + +const u32bit Square::TE0[256] = { +0x97B1B126, 0x69CECEA7, 0x73C3C3B0, 0xDF95954A, 0xB45A5AEE, 0xAFADAD02, +0x3BE7E7DC, 0x04020206, 0x9A4D4DD7, 0x884444CC, 0x03FBFBF8, 0xD7919146, +0x180C0C14, 0xFB87877C, 0xB7A1A116, 0xA05050F0, 0x63CBCBA8, 0xCE6767A9, +0xA85454FC, 0x4FDDDD92, 0x8C4646CA, 0xEB8F8F64, 0x37E1E1D6, 0x9C4E4ED2, +0x15F0F0E5, 0x0FFDFDF2, 0x0DFCFCF1, 0x23EBEBC8, 0x07F9F9FE, 0x7DC4C4B9, +0x341A1A2E, 0xDC6E6EB2, 0xBC5E5EE2, 0x1FF5F5EA, 0x6DCCCCA1, 0xEF8D8D62, +0x381C1C24, 0xAC5656FA, 0x864343C5, 0x09FEFEF7, 0x0E070709, 0xC26161A3, +0x05F8F8FD, 0xEA75759F, 0xB25959EB, 0x0BFFFFF4, 0x06030305, 0x44222266, +0xE18A8A6B, 0x57D1D186, 0x26131335, 0x29EEEEC7, 0xE588886D, 0x00000000, +0x1C0E0E12, 0x6834345C, 0x2A15153F, 0xF5808075, 0xDD949449, 0x33E3E3D0, +0x2FEDEDC2, 0x9FB5B52A, 0xA65353F5, 0x46232365, 0x964B4BDD, 0x8E4747C9, +0x2E171739, 0xBBA7A71C, 0xD5909045, 0x6A35355F, 0xA3ABAB08, 0x45D8D89D, +0x85B8B83D, 0x4BDFDF94, 0x9E4F4FD1, 0xAE5757F9, 0xC19A9A5B, 0xD1929243, +0x43DBDB98, 0x361B1B2D, 0x783C3C44, 0x65C8C8AD, 0xC799995E, 0x0804040C, +0xE98E8E67, 0x35E0E0D5, 0x5BD7D78C, 0xFA7D7D87, 0xFF85857A, 0x83BBBB38, +0x804040C0, 0x582C2C74, 0x743A3A4E, 0x8A4545CF, 0x17F1F1E6, 0x844242C6, +0xCA6565AF, 0x40202060, 0x824141C3, 0x30181828, 0xE4727296, 0x4A25256F, +0xD3939340, 0xE0707090, 0x6C36365A, 0x0A05050F, 0x11F2F2E3, 0x160B0B1D, +0xB3A3A310, 0xF279798B, 0x2DECECC1, 0x10080818, 0x4E272769, 0x62313153, +0x64323256, 0x99B6B62F, 0xF87C7C84, 0x95B0B025, 0x140A0A1E, 0xE6737395, +0xB65B5BED, 0xF67B7B8D, 0x9BB7B72C, 0xF7818176, 0x51D2D283, 0x1A0D0D17, +0xD46A6ABE, 0x4C26266A, 0xC99E9E57, 0xB05858E8, 0xCD9C9C51, 0xF3838370, +0xE874749C, 0x93B3B320, 0xADACAC01, 0x60303050, 0xF47A7A8E, 0xD26969BB, +0xEE777799, 0x1E0F0F11, 0xA9AEAE07, 0x42212163, 0x49DEDE97, 0x55D0D085, +0x5C2E2E72, 0xDB97974C, 0x20101030, 0xBDA4A419, 0xC598985D, 0xA5A8A80D, +0x5DD4D489, 0xD06868B8, 0x5A2D2D77, 0xC46262A6, 0x5229297B, 0xDA6D6DB7, +0x2C16163A, 0x924949DB, 0xEC76769A, 0x7BC7C7BC, 0x25E8E8CD, 0x77C1C1B6, +0xD996964F, 0x6E373759, 0x3FE5E5DA, 0x61CACAAB, 0x1DF4F4E9, 0x27E9E9CE, +0xC66363A5, 0x24121236, 0x71C2C2B3, 0xB9A6A61F, 0x2814143C, 0x8DBCBC31, +0x53D3D380, 0x50282878, 0xABAFAF04, 0x5E2F2F71, 0x39E6E6DF, 0x4824246C, +0xA45252F6, 0x79C6C6BF, 0xB5A0A015, 0x1209091B, 0x8FBDBD32, 0xED8C8C61, +0x6BCFCFA4, 0xBA5D5DE7, 0x22111133, 0xBE5F5FE1, 0x02010103, 0x7FC5C5BA, +0xCB9F9F54, 0x7A3D3D47, 0xB1A2A213, 0xC39B9B58, 0x67C9C9AE, 0x763B3B4D, +0x89BEBE37, 0xA25151F3, 0x3219192B, 0x3E1F1F21, 0x7E3F3F41, 0xB85C5CE4, +0x91B2B223, 0x2BEFEFC4, 0x944A4ADE, 0x6FCDCDA2, 0x8BBFBF34, 0x81BABA3B, +0xDE6F6FB1, 0xC86464AC, 0x47D9D99E, 0x13F3F3E0, 0x7C3E3E42, 0x9DB4B429, +0xA1AAAA0B, 0x4DDCDC91, 0x5FD5D58A, 0x0C06060A, 0x75C0C0B5, 0xFC7E7E82, +0x19F6F6EF, 0xCC6666AA, 0xD86C6CB4, 0xFD848479, 0xE2717193, 0x70383848, +0x87B9B93E, 0x3A1D1D27, 0xFE7F7F81, 0xCF9D9D52, 0x904848D8, 0xE38B8B68, +0x542A2A7E, 0x41DADA9B, 0xBFA5A51A, 0x66333355, 0xF1828273, 0x7239394B, +0x59D6D68F, 0xF0787888, 0xF986867F, 0x01FAFAFB, 0x3DE4E4D9, 0x562B2B7D, +0xA7A9A90E, 0x3C1E1E22, 0xE789896E, 0xC06060A0, 0xD66B6BBD, 0x21EAEACB, +0xAA5555FF, 0x984C4CD4, 0x1BF7F7EC, 0x31E2E2D3 }; + +const u32bit Square::TE1[256] = { +0x2697B1B1, 0xA769CECE, 0xB073C3C3, 0x4ADF9595, 0xEEB45A5A, 0x02AFADAD, +0xDC3BE7E7, 0x06040202, 0xD79A4D4D, 0xCC884444, 0xF803FBFB, 0x46D79191, +0x14180C0C, 0x7CFB8787, 0x16B7A1A1, 0xF0A05050, 0xA863CBCB, 0xA9CE6767, +0xFCA85454, 0x924FDDDD, 0xCA8C4646, 0x64EB8F8F, 0xD637E1E1, 0xD29C4E4E, +0xE515F0F0, 0xF20FFDFD, 0xF10DFCFC, 0xC823EBEB, 0xFE07F9F9, 0xB97DC4C4, +0x2E341A1A, 0xB2DC6E6E, 0xE2BC5E5E, 0xEA1FF5F5, 0xA16DCCCC, 0x62EF8D8D, +0x24381C1C, 0xFAAC5656, 0xC5864343, 0xF709FEFE, 0x090E0707, 0xA3C26161, +0xFD05F8F8, 0x9FEA7575, 0xEBB25959, 0xF40BFFFF, 0x05060303, 0x66442222, +0x6BE18A8A, 0x8657D1D1, 0x35261313, 0xC729EEEE, 0x6DE58888, 0x00000000, +0x121C0E0E, 0x5C683434, 0x3F2A1515, 0x75F58080, 0x49DD9494, 0xD033E3E3, +0xC22FEDED, 0x2A9FB5B5, 0xF5A65353, 0x65462323, 0xDD964B4B, 0xC98E4747, +0x392E1717, 0x1CBBA7A7, 0x45D59090, 0x5F6A3535, 0x08A3ABAB, 0x9D45D8D8, +0x3D85B8B8, 0x944BDFDF, 0xD19E4F4F, 0xF9AE5757, 0x5BC19A9A, 0x43D19292, +0x9843DBDB, 0x2D361B1B, 0x44783C3C, 0xAD65C8C8, 0x5EC79999, 0x0C080404, +0x67E98E8E, 0xD535E0E0, 0x8C5BD7D7, 0x87FA7D7D, 0x7AFF8585, 0x3883BBBB, +0xC0804040, 0x74582C2C, 0x4E743A3A, 0xCF8A4545, 0xE617F1F1, 0xC6844242, +0xAFCA6565, 0x60402020, 0xC3824141, 0x28301818, 0x96E47272, 0x6F4A2525, +0x40D39393, 0x90E07070, 0x5A6C3636, 0x0F0A0505, 0xE311F2F2, 0x1D160B0B, +0x10B3A3A3, 0x8BF27979, 0xC12DECEC, 0x18100808, 0x694E2727, 0x53623131, +0x56643232, 0x2F99B6B6, 0x84F87C7C, 0x2595B0B0, 0x1E140A0A, 0x95E67373, +0xEDB65B5B, 0x8DF67B7B, 0x2C9BB7B7, 0x76F78181, 0x8351D2D2, 0x171A0D0D, +0xBED46A6A, 0x6A4C2626, 0x57C99E9E, 0xE8B05858, 0x51CD9C9C, 0x70F38383, +0x9CE87474, 0x2093B3B3, 0x01ADACAC, 0x50603030, 0x8EF47A7A, 0xBBD26969, +0x99EE7777, 0x111E0F0F, 0x07A9AEAE, 0x63422121, 0x9749DEDE, 0x8555D0D0, +0x725C2E2E, 0x4CDB9797, 0x30201010, 0x19BDA4A4, 0x5DC59898, 0x0DA5A8A8, +0x895DD4D4, 0xB8D06868, 0x775A2D2D, 0xA6C46262, 0x7B522929, 0xB7DA6D6D, +0x3A2C1616, 0xDB924949, 0x9AEC7676, 0xBC7BC7C7, 0xCD25E8E8, 0xB677C1C1, +0x4FD99696, 0x596E3737, 0xDA3FE5E5, 0xAB61CACA, 0xE91DF4F4, 0xCE27E9E9, +0xA5C66363, 0x36241212, 0xB371C2C2, 0x1FB9A6A6, 0x3C281414, 0x318DBCBC, +0x8053D3D3, 0x78502828, 0x04ABAFAF, 0x715E2F2F, 0xDF39E6E6, 0x6C482424, +0xF6A45252, 0xBF79C6C6, 0x15B5A0A0, 0x1B120909, 0x328FBDBD, 0x61ED8C8C, +0xA46BCFCF, 0xE7BA5D5D, 0x33221111, 0xE1BE5F5F, 0x03020101, 0xBA7FC5C5, +0x54CB9F9F, 0x477A3D3D, 0x13B1A2A2, 0x58C39B9B, 0xAE67C9C9, 0x4D763B3B, +0x3789BEBE, 0xF3A25151, 0x2B321919, 0x213E1F1F, 0x417E3F3F, 0xE4B85C5C, +0x2391B2B2, 0xC42BEFEF, 0xDE944A4A, 0xA26FCDCD, 0x348BBFBF, 0x3B81BABA, +0xB1DE6F6F, 0xACC86464, 0x9E47D9D9, 0xE013F3F3, 0x427C3E3E, 0x299DB4B4, +0x0BA1AAAA, 0x914DDCDC, 0x8A5FD5D5, 0x0A0C0606, 0xB575C0C0, 0x82FC7E7E, +0xEF19F6F6, 0xAACC6666, 0xB4D86C6C, 0x79FD8484, 0x93E27171, 0x48703838, +0x3E87B9B9, 0x273A1D1D, 0x81FE7F7F, 0x52CF9D9D, 0xD8904848, 0x68E38B8B, +0x7E542A2A, 0x9B41DADA, 0x1ABFA5A5, 0x55663333, 0x73F18282, 0x4B723939, +0x8F59D6D6, 0x88F07878, 0x7FF98686, 0xFB01FAFA, 0xD93DE4E4, 0x7D562B2B, +0x0EA7A9A9, 0x223C1E1E, 0x6EE78989, 0xA0C06060, 0xBDD66B6B, 0xCB21EAEA, +0xFFAA5555, 0xD4984C4C, 0xEC1BF7F7, 0xD331E2E2 }; + +const u32bit Square::TE2[256] = { +0xB12697B1, 0xCEA769CE, 0xC3B073C3, 0x954ADF95, 0x5AEEB45A, 0xAD02AFAD, +0xE7DC3BE7, 0x02060402, 0x4DD79A4D, 0x44CC8844, 0xFBF803FB, 0x9146D791, +0x0C14180C, 0x877CFB87, 0xA116B7A1, 0x50F0A050, 0xCBA863CB, 0x67A9CE67, +0x54FCA854, 0xDD924FDD, 0x46CA8C46, 0x8F64EB8F, 0xE1D637E1, 0x4ED29C4E, +0xF0E515F0, 0xFDF20FFD, 0xFCF10DFC, 0xEBC823EB, 0xF9FE07F9, 0xC4B97DC4, +0x1A2E341A, 0x6EB2DC6E, 0x5EE2BC5E, 0xF5EA1FF5, 0xCCA16DCC, 0x8D62EF8D, +0x1C24381C, 0x56FAAC56, 0x43C58643, 0xFEF709FE, 0x07090E07, 0x61A3C261, +0xF8FD05F8, 0x759FEA75, 0x59EBB259, 0xFFF40BFF, 0x03050603, 0x22664422, +0x8A6BE18A, 0xD18657D1, 0x13352613, 0xEEC729EE, 0x886DE588, 0x00000000, +0x0E121C0E, 0x345C6834, 0x153F2A15, 0x8075F580, 0x9449DD94, 0xE3D033E3, +0xEDC22FED, 0xB52A9FB5, 0x53F5A653, 0x23654623, 0x4BDD964B, 0x47C98E47, +0x17392E17, 0xA71CBBA7, 0x9045D590, 0x355F6A35, 0xAB08A3AB, 0xD89D45D8, +0xB83D85B8, 0xDF944BDF, 0x4FD19E4F, 0x57F9AE57, 0x9A5BC19A, 0x9243D192, +0xDB9843DB, 0x1B2D361B, 0x3C44783C, 0xC8AD65C8, 0x995EC799, 0x040C0804, +0x8E67E98E, 0xE0D535E0, 0xD78C5BD7, 0x7D87FA7D, 0x857AFF85, 0xBB3883BB, +0x40C08040, 0x2C74582C, 0x3A4E743A, 0x45CF8A45, 0xF1E617F1, 0x42C68442, +0x65AFCA65, 0x20604020, 0x41C38241, 0x18283018, 0x7296E472, 0x256F4A25, +0x9340D393, 0x7090E070, 0x365A6C36, 0x050F0A05, 0xF2E311F2, 0x0B1D160B, +0xA310B3A3, 0x798BF279, 0xECC12DEC, 0x08181008, 0x27694E27, 0x31536231, +0x32566432, 0xB62F99B6, 0x7C84F87C, 0xB02595B0, 0x0A1E140A, 0x7395E673, +0x5BEDB65B, 0x7B8DF67B, 0xB72C9BB7, 0x8176F781, 0xD28351D2, 0x0D171A0D, +0x6ABED46A, 0x266A4C26, 0x9E57C99E, 0x58E8B058, 0x9C51CD9C, 0x8370F383, +0x749CE874, 0xB32093B3, 0xAC01ADAC, 0x30506030, 0x7A8EF47A, 0x69BBD269, +0x7799EE77, 0x0F111E0F, 0xAE07A9AE, 0x21634221, 0xDE9749DE, 0xD08555D0, +0x2E725C2E, 0x974CDB97, 0x10302010, 0xA419BDA4, 0x985DC598, 0xA80DA5A8, +0xD4895DD4, 0x68B8D068, 0x2D775A2D, 0x62A6C462, 0x297B5229, 0x6DB7DA6D, +0x163A2C16, 0x49DB9249, 0x769AEC76, 0xC7BC7BC7, 0xE8CD25E8, 0xC1B677C1, +0x964FD996, 0x37596E37, 0xE5DA3FE5, 0xCAAB61CA, 0xF4E91DF4, 0xE9CE27E9, +0x63A5C663, 0x12362412, 0xC2B371C2, 0xA61FB9A6, 0x143C2814, 0xBC318DBC, +0xD38053D3, 0x28785028, 0xAF04ABAF, 0x2F715E2F, 0xE6DF39E6, 0x246C4824, +0x52F6A452, 0xC6BF79C6, 0xA015B5A0, 0x091B1209, 0xBD328FBD, 0x8C61ED8C, +0xCFA46BCF, 0x5DE7BA5D, 0x11332211, 0x5FE1BE5F, 0x01030201, 0xC5BA7FC5, +0x9F54CB9F, 0x3D477A3D, 0xA213B1A2, 0x9B58C39B, 0xC9AE67C9, 0x3B4D763B, +0xBE3789BE, 0x51F3A251, 0x192B3219, 0x1F213E1F, 0x3F417E3F, 0x5CE4B85C, +0xB22391B2, 0xEFC42BEF, 0x4ADE944A, 0xCDA26FCD, 0xBF348BBF, 0xBA3B81BA, +0x6FB1DE6F, 0x64ACC864, 0xD99E47D9, 0xF3E013F3, 0x3E427C3E, 0xB4299DB4, +0xAA0BA1AA, 0xDC914DDC, 0xD58A5FD5, 0x060A0C06, 0xC0B575C0, 0x7E82FC7E, +0xF6EF19F6, 0x66AACC66, 0x6CB4D86C, 0x8479FD84, 0x7193E271, 0x38487038, +0xB93E87B9, 0x1D273A1D, 0x7F81FE7F, 0x9D52CF9D, 0x48D89048, 0x8B68E38B, +0x2A7E542A, 0xDA9B41DA, 0xA51ABFA5, 0x33556633, 0x8273F182, 0x394B7239, +0xD68F59D6, 0x7888F078, 0x867FF986, 0xFAFB01FA, 0xE4D93DE4, 0x2B7D562B, +0xA90EA7A9, 0x1E223C1E, 0x896EE789, 0x60A0C060, 0x6BBDD66B, 0xEACB21EA, +0x55FFAA55, 0x4CD4984C, 0xF7EC1BF7, 0xE2D331E2 }; + +const u32bit Square::TE3[256] = { +0xB1B12697, 0xCECEA769, 0xC3C3B073, 0x95954ADF, 0x5A5AEEB4, 0xADAD02AF, +0xE7E7DC3B, 0x02020604, 0x4D4DD79A, 0x4444CC88, 0xFBFBF803, 0x919146D7, +0x0C0C1418, 0x87877CFB, 0xA1A116B7, 0x5050F0A0, 0xCBCBA863, 0x6767A9CE, +0x5454FCA8, 0xDDDD924F, 0x4646CA8C, 0x8F8F64EB, 0xE1E1D637, 0x4E4ED29C, +0xF0F0E515, 0xFDFDF20F, 0xFCFCF10D, 0xEBEBC823, 0xF9F9FE07, 0xC4C4B97D, +0x1A1A2E34, 0x6E6EB2DC, 0x5E5EE2BC, 0xF5F5EA1F, 0xCCCCA16D, 0x8D8D62EF, +0x1C1C2438, 0x5656FAAC, 0x4343C586, 0xFEFEF709, 0x0707090E, 0x6161A3C2, +0xF8F8FD05, 0x75759FEA, 0x5959EBB2, 0xFFFFF40B, 0x03030506, 0x22226644, +0x8A8A6BE1, 0xD1D18657, 0x13133526, 0xEEEEC729, 0x88886DE5, 0x00000000, +0x0E0E121C, 0x34345C68, 0x15153F2A, 0x808075F5, 0x949449DD, 0xE3E3D033, +0xEDEDC22F, 0xB5B52A9F, 0x5353F5A6, 0x23236546, 0x4B4BDD96, 0x4747C98E, +0x1717392E, 0xA7A71CBB, 0x909045D5, 0x35355F6A, 0xABAB08A3, 0xD8D89D45, +0xB8B83D85, 0xDFDF944B, 0x4F4FD19E, 0x5757F9AE, 0x9A9A5BC1, 0x929243D1, +0xDBDB9843, 0x1B1B2D36, 0x3C3C4478, 0xC8C8AD65, 0x99995EC7, 0x04040C08, +0x8E8E67E9, 0xE0E0D535, 0xD7D78C5B, 0x7D7D87FA, 0x85857AFF, 0xBBBB3883, +0x4040C080, 0x2C2C7458, 0x3A3A4E74, 0x4545CF8A, 0xF1F1E617, 0x4242C684, +0x6565AFCA, 0x20206040, 0x4141C382, 0x18182830, 0x727296E4, 0x25256F4A, +0x939340D3, 0x707090E0, 0x36365A6C, 0x05050F0A, 0xF2F2E311, 0x0B0B1D16, +0xA3A310B3, 0x79798BF2, 0xECECC12D, 0x08081810, 0x2727694E, 0x31315362, +0x32325664, 0xB6B62F99, 0x7C7C84F8, 0xB0B02595, 0x0A0A1E14, 0x737395E6, +0x5B5BEDB6, 0x7B7B8DF6, 0xB7B72C9B, 0x818176F7, 0xD2D28351, 0x0D0D171A, +0x6A6ABED4, 0x26266A4C, 0x9E9E57C9, 0x5858E8B0, 0x9C9C51CD, 0x838370F3, +0x74749CE8, 0xB3B32093, 0xACAC01AD, 0x30305060, 0x7A7A8EF4, 0x6969BBD2, +0x777799EE, 0x0F0F111E, 0xAEAE07A9, 0x21216342, 0xDEDE9749, 0xD0D08555, +0x2E2E725C, 0x97974CDB, 0x10103020, 0xA4A419BD, 0x98985DC5, 0xA8A80DA5, +0xD4D4895D, 0x6868B8D0, 0x2D2D775A, 0x6262A6C4, 0x29297B52, 0x6D6DB7DA, +0x16163A2C, 0x4949DB92, 0x76769AEC, 0xC7C7BC7B, 0xE8E8CD25, 0xC1C1B677, +0x96964FD9, 0x3737596E, 0xE5E5DA3F, 0xCACAAB61, 0xF4F4E91D, 0xE9E9CE27, +0x6363A5C6, 0x12123624, 0xC2C2B371, 0xA6A61FB9, 0x14143C28, 0xBCBC318D, +0xD3D38053, 0x28287850, 0xAFAF04AB, 0x2F2F715E, 0xE6E6DF39, 0x24246C48, +0x5252F6A4, 0xC6C6BF79, 0xA0A015B5, 0x09091B12, 0xBDBD328F, 0x8C8C61ED, +0xCFCFA46B, 0x5D5DE7BA, 0x11113322, 0x5F5FE1BE, 0x01010302, 0xC5C5BA7F, +0x9F9F54CB, 0x3D3D477A, 0xA2A213B1, 0x9B9B58C3, 0xC9C9AE67, 0x3B3B4D76, +0xBEBE3789, 0x5151F3A2, 0x19192B32, 0x1F1F213E, 0x3F3F417E, 0x5C5CE4B8, +0xB2B22391, 0xEFEFC42B, 0x4A4ADE94, 0xCDCDA26F, 0xBFBF348B, 0xBABA3B81, +0x6F6FB1DE, 0x6464ACC8, 0xD9D99E47, 0xF3F3E013, 0x3E3E427C, 0xB4B4299D, +0xAAAA0BA1, 0xDCDC914D, 0xD5D58A5F, 0x06060A0C, 0xC0C0B575, 0x7E7E82FC, +0xF6F6EF19, 0x6666AACC, 0x6C6CB4D8, 0x848479FD, 0x717193E2, 0x38384870, +0xB9B93E87, 0x1D1D273A, 0x7F7F81FE, 0x9D9D52CF, 0x4848D890, 0x8B8B68E3, +0x2A2A7E54, 0xDADA9B41, 0xA5A51ABF, 0x33335566, 0x828273F1, 0x39394B72, +0xD6D68F59, 0x787888F0, 0x86867FF9, 0xFAFAFB01, 0xE4E4D93D, 0x2B2B7D56, +0xA9A90EA7, 0x1E1E223C, 0x89896EE7, 0x6060A0C0, 0x6B6BBDD6, 0xEAEACB21, +0x5555FFAA, 0x4C4CD498, 0xF7F7EC1B, 0xE2E2D331 }; + +const u32bit Square::TD0[256] = { +0xE368BC02, 0x5585620C, 0x2A3F2331, 0x61AB13F7, 0x98D46D72, 0x21CB9A19, +0x3C22A461, 0x459D3DCD, 0x05FDB423, 0x2BC4075F, 0x9B2C01C0, 0x3DD9800F, +0x486C5C74, 0xF97F7E85, 0xF173AB1F, 0xB6EDDE0E, 0x283C6BED, 0x4997781A, +0x9F2A918D, 0xC9579F33, 0xA907A8AA, 0xA50DED7D, 0x7C422D8F, 0x764DB0C9, +0x4D91E857, 0xCEA963CC, 0xB4EE96D2, 0x3028E1B6, 0x0DF161B9, 0xBD196726, +0x419BAD80, 0xC0A06EC7, 0x5183F241, 0x92DBF034, 0x6FA21EFC, 0x8F32CE4C, +0x13E03373, 0x69A7C66D, 0xE56D6493, 0xBF1A2FFA, 0xBB1CBFB7, 0x587403B5, +0xE76E2C4F, 0x5D89B796, 0xE89C052A, 0x446619A3, 0x342E71FB, 0x0FF22965, +0xFE81827A, 0xB11322F1, 0xA30835EC, 0xCD510F7E, 0xFF7AA614, 0x5C7293F8, +0x2FC29712, 0xF370E3C3, 0x992F491C, 0xD1431568, 0xC2A3261B, 0x88CC32B3, +0x8ACF7A6F, 0xB0E8069F, 0x7A47F51E, 0xD2BB79DA, 0xE6950821, 0x4398E55C, +0xD0B83106, 0x11E37BAF, 0x7E416553, 0xCCAA2B10, 0xD8B4E49C, 0x6456A7D4, +0xFB7C3659, 0x724B2084, 0xEA9F4DF6, 0x6A5FAADF, 0x2DC1DFCE, 0x70486858, +0xCAAFF381, 0x0605D891, 0x5A774B69, 0x94DE28A5, 0x39DF1042, 0x813BC347, +0xFC82CAA6, 0x23C8D2C5, 0x03F86CB2, 0x080CD59A, 0xDAB7AC40, 0x7DB909E1, +0x3824342C, 0xCF5247A2, 0xDCB274D1, 0x63A85B2B, 0x35D55595, 0x479E7511, +0x15E5EBE2, 0x4B9430C6, 0x4A6F14A8, 0x91239C86, 0x4C6ACC39, 0x5F8AFF4A, +0x0406904D, 0xEE99DDBB, 0x1E1152CA, 0xAAFFC418, 0xEB646998, 0x07FEFCFF, +0x8B345E01, 0x567D0EBE, 0xBAE79BD9, 0x4263C132, 0x75B5DC7B, 0x97264417, +0x67AECB66, 0x95250CCB, 0xEC9A9567, 0x57862AD0, 0x60503799, 0xB8E4D305, +0x65AD83BA, 0x19EFAE35, 0xA4F6C913, 0xC15B4AA9, 0x873E1BD6, 0xA0F0595E, +0x18148A5B, 0xAF02703B, 0xAB04E076, 0xDD4950BF, 0xDF4A1863, 0xC6A5B656, +0x853D530A, 0xFA871237, 0x77B694A7, 0x4665517F, 0xED61B109, 0x1BECE6E9, +0xD5458525, 0xF5753B52, 0x7FBA413D, 0x27CE4288, 0xB2EB4E43, 0xD6BDE997, +0x527B9EF3, 0x62537F45, 0x2C3AFBA0, 0x7BBCD170, 0xB91FF76B, 0x121B171D, +0xFD79EEC8, 0x3A277CF0, 0x0C0A45D7, 0x96DD6079, 0x2233F6AB, 0xACFA1C89, +0xC8ACBB5D, 0xA10B7D30, 0xD4BEA14B, 0xBEE10B94, 0x25CD0A54, 0x547E4662, +0xA2F31182, 0x17E6A33E, 0x263566E6, 0xC3580275, 0x83388B9B, 0x7844BDC2, +0x020348DC, 0x4F92A08B, 0x2E39B37C, 0x4E6984E5, 0xF0888F71, 0x362D3927, +0x9CD2FD3F, 0x01FB246E, 0x893716DD, 0x00000000, 0xF68D57E0, 0xE293986C, +0x744EF815, 0x9320D45A, 0xAD0138E7, 0xD3405DB4, 0x1A17C287, 0xB3106A2D, +0x5078D62F, 0xF48E1F3C, 0xA70EA5A1, 0x71B34C36, 0x9AD725AE, 0x5E71DB24, +0x161D8750, 0xEF62F9D5, 0x8D318690, 0x1C121A16, 0xA6F581CF, 0x5B8C6F07, +0x37D61D49, 0x6E593A92, 0x84C67764, 0x86C53FB8, 0xD746CDF9, 0xE090D0B0, +0x29C74F83, 0xE49640FD, 0x0E090D0B, 0x6DA15620, 0x8EC9EA22, 0xDB4C882E, +0xF776738E, 0xB515B2BC, 0x10185FC1, 0x322BA96A, 0x6BA48EB1, 0xAEF95455, +0x406089EE, 0x6655EF08, 0xE9672144, 0x3E21ECBD, 0x2030BE77, 0xF28BC7AD, +0x80C0E729, 0x141ECF8C, 0xBCE24348, 0xC4A6FE8A, 0x31D3C5D8, 0xB716FA60, +0x5380BA9D, 0xD94FC0F2, 0x1DE93E78, 0x24362E3A, 0xE16BF4DE, 0xCB54D7EF, +0x09F7F1F4, 0x82C3AFF5, 0x0BF4B928, 0x9D29D951, 0xC75E9238, 0xF8845AEB, +0x90D8B8E8, 0xDEB13C0D, 0x33D08D04, 0x685CE203, 0xC55DDAE4, 0x3BDC589E, +0x0A0F9D46, 0x3FDAC8D3, 0x598F27DB, 0xA8FC8CC4, 0x79BF99AC, 0x6C5A724E, +0x8CCAA2FE, 0x9ED1B5E3, 0x1FEA76A4, 0x73B004EA }; + +const u32bit Square::TD1[256] = { +0x02E368BC, 0x0C558562, 0x312A3F23, 0xF761AB13, 0x7298D46D, 0x1921CB9A, +0x613C22A4, 0xCD459D3D, 0x2305FDB4, 0x5F2BC407, 0xC09B2C01, 0x0F3DD980, +0x74486C5C, 0x85F97F7E, 0x1FF173AB, 0x0EB6EDDE, 0xED283C6B, 0x1A499778, +0x8D9F2A91, 0x33C9579F, 0xAAA907A8, 0x7DA50DED, 0x8F7C422D, 0xC9764DB0, +0x574D91E8, 0xCCCEA963, 0xD2B4EE96, 0xB63028E1, 0xB90DF161, 0x26BD1967, +0x80419BAD, 0xC7C0A06E, 0x415183F2, 0x3492DBF0, 0xFC6FA21E, 0x4C8F32CE, +0x7313E033, 0x6D69A7C6, 0x93E56D64, 0xFABF1A2F, 0xB7BB1CBF, 0xB5587403, +0x4FE76E2C, 0x965D89B7, 0x2AE89C05, 0xA3446619, 0xFB342E71, 0x650FF229, +0x7AFE8182, 0xF1B11322, 0xECA30835, 0x7ECD510F, 0x14FF7AA6, 0xF85C7293, +0x122FC297, 0xC3F370E3, 0x1C992F49, 0x68D14315, 0x1BC2A326, 0xB388CC32, +0x6F8ACF7A, 0x9FB0E806, 0x1E7A47F5, 0xDAD2BB79, 0x21E69508, 0x5C4398E5, +0x06D0B831, 0xAF11E37B, 0x537E4165, 0x10CCAA2B, 0x9CD8B4E4, 0xD46456A7, +0x59FB7C36, 0x84724B20, 0xF6EA9F4D, 0xDF6A5FAA, 0xCE2DC1DF, 0x58704868, +0x81CAAFF3, 0x910605D8, 0x695A774B, 0xA594DE28, 0x4239DF10, 0x47813BC3, +0xA6FC82CA, 0xC523C8D2, 0xB203F86C, 0x9A080CD5, 0x40DAB7AC, 0xE17DB909, +0x2C382434, 0xA2CF5247, 0xD1DCB274, 0x2B63A85B, 0x9535D555, 0x11479E75, +0xE215E5EB, 0xC64B9430, 0xA84A6F14, 0x8691239C, 0x394C6ACC, 0x4A5F8AFF, +0x4D040690, 0xBBEE99DD, 0xCA1E1152, 0x18AAFFC4, 0x98EB6469, 0xFF07FEFC, +0x018B345E, 0xBE567D0E, 0xD9BAE79B, 0x324263C1, 0x7B75B5DC, 0x17972644, +0x6667AECB, 0xCB95250C, 0x67EC9A95, 0xD057862A, 0x99605037, 0x05B8E4D3, +0xBA65AD83, 0x3519EFAE, 0x13A4F6C9, 0xA9C15B4A, 0xD6873E1B, 0x5EA0F059, +0x5B18148A, 0x3BAF0270, 0x76AB04E0, 0xBFDD4950, 0x63DF4A18, 0x56C6A5B6, +0x0A853D53, 0x37FA8712, 0xA777B694, 0x7F466551, 0x09ED61B1, 0xE91BECE6, +0x25D54585, 0x52F5753B, 0x3D7FBA41, 0x8827CE42, 0x43B2EB4E, 0x97D6BDE9, +0xF3527B9E, 0x4562537F, 0xA02C3AFB, 0x707BBCD1, 0x6BB91FF7, 0x1D121B17, +0xC8FD79EE, 0xF03A277C, 0xD70C0A45, 0x7996DD60, 0xAB2233F6, 0x89ACFA1C, +0x5DC8ACBB, 0x30A10B7D, 0x4BD4BEA1, 0x94BEE10B, 0x5425CD0A, 0x62547E46, +0x82A2F311, 0x3E17E6A3, 0xE6263566, 0x75C35802, 0x9B83388B, 0xC27844BD, +0xDC020348, 0x8B4F92A0, 0x7C2E39B3, 0xE54E6984, 0x71F0888F, 0x27362D39, +0x3F9CD2FD, 0x6E01FB24, 0xDD893716, 0x00000000, 0xE0F68D57, 0x6CE29398, +0x15744EF8, 0x5A9320D4, 0xE7AD0138, 0xB4D3405D, 0x871A17C2, 0x2DB3106A, +0x2F5078D6, 0x3CF48E1F, 0xA1A70EA5, 0x3671B34C, 0xAE9AD725, 0x245E71DB, +0x50161D87, 0xD5EF62F9, 0x908D3186, 0x161C121A, 0xCFA6F581, 0x075B8C6F, +0x4937D61D, 0x926E593A, 0x6484C677, 0xB886C53F, 0xF9D746CD, 0xB0E090D0, +0x8329C74F, 0xFDE49640, 0x0B0E090D, 0x206DA156, 0x228EC9EA, 0x2EDB4C88, +0x8EF77673, 0xBCB515B2, 0xC110185F, 0x6A322BA9, 0xB16BA48E, 0x55AEF954, +0xEE406089, 0x086655EF, 0x44E96721, 0xBD3E21EC, 0x772030BE, 0xADF28BC7, +0x2980C0E7, 0x8C141ECF, 0x48BCE243, 0x8AC4A6FE, 0xD831D3C5, 0x60B716FA, +0x9D5380BA, 0xF2D94FC0, 0x781DE93E, 0x3A24362E, 0xDEE16BF4, 0xEFCB54D7, +0xF409F7F1, 0xF582C3AF, 0x280BF4B9, 0x519D29D9, 0x38C75E92, 0xEBF8845A, +0xE890D8B8, 0x0DDEB13C, 0x0433D08D, 0x03685CE2, 0xE4C55DDA, 0x9E3BDC58, +0x460A0F9D, 0xD33FDAC8, 0xDB598F27, 0xC4A8FC8C, 0xAC79BF99, 0x4E6C5A72, +0xFE8CCAA2, 0xE39ED1B5, 0xA41FEA76, 0xEA73B004 }; + +const u32bit Square::TD2[256] = { +0xBC02E368, 0x620C5585, 0x23312A3F, 0x13F761AB, 0x6D7298D4, 0x9A1921CB, +0xA4613C22, 0x3DCD459D, 0xB42305FD, 0x075F2BC4, 0x01C09B2C, 0x800F3DD9, +0x5C74486C, 0x7E85F97F, 0xAB1FF173, 0xDE0EB6ED, 0x6BED283C, 0x781A4997, +0x918D9F2A, 0x9F33C957, 0xA8AAA907, 0xED7DA50D, 0x2D8F7C42, 0xB0C9764D, +0xE8574D91, 0x63CCCEA9, 0x96D2B4EE, 0xE1B63028, 0x61B90DF1, 0x6726BD19, +0xAD80419B, 0x6EC7C0A0, 0xF2415183, 0xF03492DB, 0x1EFC6FA2, 0xCE4C8F32, +0x337313E0, 0xC66D69A7, 0x6493E56D, 0x2FFABF1A, 0xBFB7BB1C, 0x03B55874, +0x2C4FE76E, 0xB7965D89, 0x052AE89C, 0x19A34466, 0x71FB342E, 0x29650FF2, +0x827AFE81, 0x22F1B113, 0x35ECA308, 0x0F7ECD51, 0xA614FF7A, 0x93F85C72, +0x97122FC2, 0xE3C3F370, 0x491C992F, 0x1568D143, 0x261BC2A3, 0x32B388CC, +0x7A6F8ACF, 0x069FB0E8, 0xF51E7A47, 0x79DAD2BB, 0x0821E695, 0xE55C4398, +0x3106D0B8, 0x7BAF11E3, 0x65537E41, 0x2B10CCAA, 0xE49CD8B4, 0xA7D46456, +0x3659FB7C, 0x2084724B, 0x4DF6EA9F, 0xAADF6A5F, 0xDFCE2DC1, 0x68587048, +0xF381CAAF, 0xD8910605, 0x4B695A77, 0x28A594DE, 0x104239DF, 0xC347813B, +0xCAA6FC82, 0xD2C523C8, 0x6CB203F8, 0xD59A080C, 0xAC40DAB7, 0x09E17DB9, +0x342C3824, 0x47A2CF52, 0x74D1DCB2, 0x5B2B63A8, 0x559535D5, 0x7511479E, +0xEBE215E5, 0x30C64B94, 0x14A84A6F, 0x9C869123, 0xCC394C6A, 0xFF4A5F8A, +0x904D0406, 0xDDBBEE99, 0x52CA1E11, 0xC418AAFF, 0x6998EB64, 0xFCFF07FE, +0x5E018B34, 0x0EBE567D, 0x9BD9BAE7, 0xC1324263, 0xDC7B75B5, 0x44179726, +0xCB6667AE, 0x0CCB9525, 0x9567EC9A, 0x2AD05786, 0x37996050, 0xD305B8E4, +0x83BA65AD, 0xAE3519EF, 0xC913A4F6, 0x4AA9C15B, 0x1BD6873E, 0x595EA0F0, +0x8A5B1814, 0x703BAF02, 0xE076AB04, 0x50BFDD49, 0x1863DF4A, 0xB656C6A5, +0x530A853D, 0x1237FA87, 0x94A777B6, 0x517F4665, 0xB109ED61, 0xE6E91BEC, +0x8525D545, 0x3B52F575, 0x413D7FBA, 0x428827CE, 0x4E43B2EB, 0xE997D6BD, +0x9EF3527B, 0x7F456253, 0xFBA02C3A, 0xD1707BBC, 0xF76BB91F, 0x171D121B, +0xEEC8FD79, 0x7CF03A27, 0x45D70C0A, 0x607996DD, 0xF6AB2233, 0x1C89ACFA, +0xBB5DC8AC, 0x7D30A10B, 0xA14BD4BE, 0x0B94BEE1, 0x0A5425CD, 0x4662547E, +0x1182A2F3, 0xA33E17E6, 0x66E62635, 0x0275C358, 0x8B9B8338, 0xBDC27844, +0x48DC0203, 0xA08B4F92, 0xB37C2E39, 0x84E54E69, 0x8F71F088, 0x3927362D, +0xFD3F9CD2, 0x246E01FB, 0x16DD8937, 0x00000000, 0x57E0F68D, 0x986CE293, +0xF815744E, 0xD45A9320, 0x38E7AD01, 0x5DB4D340, 0xC2871A17, 0x6A2DB310, +0xD62F5078, 0x1F3CF48E, 0xA5A1A70E, 0x4C3671B3, 0x25AE9AD7, 0xDB245E71, +0x8750161D, 0xF9D5EF62, 0x86908D31, 0x1A161C12, 0x81CFA6F5, 0x6F075B8C, +0x1D4937D6, 0x3A926E59, 0x776484C6, 0x3FB886C5, 0xCDF9D746, 0xD0B0E090, +0x4F8329C7, 0x40FDE496, 0x0D0B0E09, 0x56206DA1, 0xEA228EC9, 0x882EDB4C, +0x738EF776, 0xB2BCB515, 0x5FC11018, 0xA96A322B, 0x8EB16BA4, 0x5455AEF9, +0x89EE4060, 0xEF086655, 0x2144E967, 0xECBD3E21, 0xBE772030, 0xC7ADF28B, +0xE72980C0, 0xCF8C141E, 0x4348BCE2, 0xFE8AC4A6, 0xC5D831D3, 0xFA60B716, +0xBA9D5380, 0xC0F2D94F, 0x3E781DE9, 0x2E3A2436, 0xF4DEE16B, 0xD7EFCB54, +0xF1F409F7, 0xAFF582C3, 0xB9280BF4, 0xD9519D29, 0x9238C75E, 0x5AEBF884, +0xB8E890D8, 0x3C0DDEB1, 0x8D0433D0, 0xE203685C, 0xDAE4C55D, 0x589E3BDC, +0x9D460A0F, 0xC8D33FDA, 0x27DB598F, 0x8CC4A8FC, 0x99AC79BF, 0x724E6C5A, +0xA2FE8CCA, 0xB5E39ED1, 0x76A41FEA, 0x04EA73B0 }; + +const u32bit Square::TD3[256] = { +0x68BC02E3, 0x85620C55, 0x3F23312A, 0xAB13F761, 0xD46D7298, 0xCB9A1921, +0x22A4613C, 0x9D3DCD45, 0xFDB42305, 0xC4075F2B, 0x2C01C09B, 0xD9800F3D, +0x6C5C7448, 0x7F7E85F9, 0x73AB1FF1, 0xEDDE0EB6, 0x3C6BED28, 0x97781A49, +0x2A918D9F, 0x579F33C9, 0x07A8AAA9, 0x0DED7DA5, 0x422D8F7C, 0x4DB0C976, +0x91E8574D, 0xA963CCCE, 0xEE96D2B4, 0x28E1B630, 0xF161B90D, 0x196726BD, +0x9BAD8041, 0xA06EC7C0, 0x83F24151, 0xDBF03492, 0xA21EFC6F, 0x32CE4C8F, +0xE0337313, 0xA7C66D69, 0x6D6493E5, 0x1A2FFABF, 0x1CBFB7BB, 0x7403B558, +0x6E2C4FE7, 0x89B7965D, 0x9C052AE8, 0x6619A344, 0x2E71FB34, 0xF229650F, +0x81827AFE, 0x1322F1B1, 0x0835ECA3, 0x510F7ECD, 0x7AA614FF, 0x7293F85C, +0xC297122F, 0x70E3C3F3, 0x2F491C99, 0x431568D1, 0xA3261BC2, 0xCC32B388, +0xCF7A6F8A, 0xE8069FB0, 0x47F51E7A, 0xBB79DAD2, 0x950821E6, 0x98E55C43, +0xB83106D0, 0xE37BAF11, 0x4165537E, 0xAA2B10CC, 0xB4E49CD8, 0x56A7D464, +0x7C3659FB, 0x4B208472, 0x9F4DF6EA, 0x5FAADF6A, 0xC1DFCE2D, 0x48685870, +0xAFF381CA, 0x05D89106, 0x774B695A, 0xDE28A594, 0xDF104239, 0x3BC34781, +0x82CAA6FC, 0xC8D2C523, 0xF86CB203, 0x0CD59A08, 0xB7AC40DA, 0xB909E17D, +0x24342C38, 0x5247A2CF, 0xB274D1DC, 0xA85B2B63, 0xD5559535, 0x9E751147, +0xE5EBE215, 0x9430C64B, 0x6F14A84A, 0x239C8691, 0x6ACC394C, 0x8AFF4A5F, +0x06904D04, 0x99DDBBEE, 0x1152CA1E, 0xFFC418AA, 0x646998EB, 0xFEFCFF07, +0x345E018B, 0x7D0EBE56, 0xE79BD9BA, 0x63C13242, 0xB5DC7B75, 0x26441797, +0xAECB6667, 0x250CCB95, 0x9A9567EC, 0x862AD057, 0x50379960, 0xE4D305B8, +0xAD83BA65, 0xEFAE3519, 0xF6C913A4, 0x5B4AA9C1, 0x3E1BD687, 0xF0595EA0, +0x148A5B18, 0x02703BAF, 0x04E076AB, 0x4950BFDD, 0x4A1863DF, 0xA5B656C6, +0x3D530A85, 0x871237FA, 0xB694A777, 0x65517F46, 0x61B109ED, 0xECE6E91B, +0x458525D5, 0x753B52F5, 0xBA413D7F, 0xCE428827, 0xEB4E43B2, 0xBDE997D6, +0x7B9EF352, 0x537F4562, 0x3AFBA02C, 0xBCD1707B, 0x1FF76BB9, 0x1B171D12, +0x79EEC8FD, 0x277CF03A, 0x0A45D70C, 0xDD607996, 0x33F6AB22, 0xFA1C89AC, +0xACBB5DC8, 0x0B7D30A1, 0xBEA14BD4, 0xE10B94BE, 0xCD0A5425, 0x7E466254, +0xF31182A2, 0xE6A33E17, 0x3566E626, 0x580275C3, 0x388B9B83, 0x44BDC278, +0x0348DC02, 0x92A08B4F, 0x39B37C2E, 0x6984E54E, 0x888F71F0, 0x2D392736, +0xD2FD3F9C, 0xFB246E01, 0x3716DD89, 0x00000000, 0x8D57E0F6, 0x93986CE2, +0x4EF81574, 0x20D45A93, 0x0138E7AD, 0x405DB4D3, 0x17C2871A, 0x106A2DB3, +0x78D62F50, 0x8E1F3CF4, 0x0EA5A1A7, 0xB34C3671, 0xD725AE9A, 0x71DB245E, +0x1D875016, 0x62F9D5EF, 0x3186908D, 0x121A161C, 0xF581CFA6, 0x8C6F075B, +0xD61D4937, 0x593A926E, 0xC6776484, 0xC53FB886, 0x46CDF9D7, 0x90D0B0E0, +0xC74F8329, 0x9640FDE4, 0x090D0B0E, 0xA156206D, 0xC9EA228E, 0x4C882EDB, +0x76738EF7, 0x15B2BCB5, 0x185FC110, 0x2BA96A32, 0xA48EB16B, 0xF95455AE, +0x6089EE40, 0x55EF0866, 0x672144E9, 0x21ECBD3E, 0x30BE7720, 0x8BC7ADF2, +0xC0E72980, 0x1ECF8C14, 0xE24348BC, 0xA6FE8AC4, 0xD3C5D831, 0x16FA60B7, +0x80BA9D53, 0x4FC0F2D9, 0xE93E781D, 0x362E3A24, 0x6BF4DEE1, 0x54D7EFCB, +0xF7F1F409, 0xC3AFF582, 0xF4B9280B, 0x29D9519D, 0x5E9238C7, 0x845AEBF8, +0xD8B8E890, 0xB13C0DDE, 0xD08D0433, 0x5CE20368, 0x5DDAE4C5, 0xDC589E3B, +0x0F9D460A, 0xDAC8D33F, 0x8F27DB59, 0xFC8CC4A8, 0xBF99AC79, 0x5A724E6C, +0xCAA2FE8C, 0xD1B5E39E, 0xEA76A41F, 0xB004EA73 }; + +} +/* +* Square +* (C) 1999-2007 Jack Lloyd +* +* Based on the public domain reference implemenation +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Square Encryption +*/ +void Square::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0, B1, B2, B3; + + B0 = TE0[in[ 0] ^ ME[ 0]] ^ TE1[in[ 4] ^ ME[ 4]] ^ + TE2[in[ 8] ^ ME[ 8]] ^ TE3[in[12] ^ ME[12]] ^ EK[0]; + B1 = TE0[in[ 1] ^ ME[ 1]] ^ TE1[in[ 5] ^ ME[ 5]] ^ + TE2[in[ 9] ^ ME[ 9]] ^ TE3[in[13] ^ ME[13]] ^ EK[1]; + B2 = TE0[in[ 2] ^ ME[ 2]] ^ TE1[in[ 6] ^ ME[ 6]] ^ + TE2[in[10] ^ ME[10]] ^ TE3[in[14] ^ ME[14]] ^ EK[2]; + B3 = TE0[in[ 3] ^ ME[ 3]] ^ TE1[in[ 7] ^ ME[ 7]] ^ + TE2[in[11] ^ ME[11]] ^ TE3[in[15] ^ ME[15]] ^ EK[3]; + + for(size_t j = 1; j != 7; j += 2) + { + u32bit T0, T1, T2, T3; + T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(0, B1)] ^ + TE2[get_byte(0, B2)] ^ TE3[get_byte(0, B3)] ^ EK[4*j+0]; + T1 = TE0[get_byte(1, B0)] ^ TE1[get_byte(1, B1)] ^ + TE2[get_byte(1, B2)] ^ TE3[get_byte(1, B3)] ^ EK[4*j+1]; + T2 = TE0[get_byte(2, B0)] ^ TE1[get_byte(2, B1)] ^ + TE2[get_byte(2, B2)] ^ TE3[get_byte(2, B3)] ^ EK[4*j+2]; + T3 = TE0[get_byte(3, B0)] ^ TE1[get_byte(3, B1)] ^ + TE2[get_byte(3, B2)] ^ TE3[get_byte(3, B3)] ^ EK[4*j+3]; + + B0 = TE0[get_byte(0, T0)] ^ TE1[get_byte(0, T1)] ^ + TE2[get_byte(0, T2)] ^ TE3[get_byte(0, T3)] ^ EK[4*j+4]; + B1 = TE0[get_byte(1, T0)] ^ TE1[get_byte(1, T1)] ^ + TE2[get_byte(1, T2)] ^ TE3[get_byte(1, T3)] ^ EK[4*j+5]; + B2 = TE0[get_byte(2, T0)] ^ TE1[get_byte(2, T1)] ^ + TE2[get_byte(2, T2)] ^ TE3[get_byte(2, T3)] ^ EK[4*j+6]; + B3 = TE0[get_byte(3, T0)] ^ TE1[get_byte(3, T1)] ^ + TE2[get_byte(3, T2)] ^ TE3[get_byte(3, T3)] ^ EK[4*j+7]; + } + + out[ 0] = SE[get_byte(0, B0)] ^ ME[16]; + out[ 1] = SE[get_byte(0, B1)] ^ ME[17]; + out[ 2] = SE[get_byte(0, B2)] ^ ME[18]; + out[ 3] = SE[get_byte(0, B3)] ^ ME[19]; + out[ 4] = SE[get_byte(1, B0)] ^ ME[20]; + out[ 5] = SE[get_byte(1, B1)] ^ ME[21]; + out[ 6] = SE[get_byte(1, B2)] ^ ME[22]; + out[ 7] = SE[get_byte(1, B3)] ^ ME[23]; + out[ 8] = SE[get_byte(2, B0)] ^ ME[24]; + out[ 9] = SE[get_byte(2, B1)] ^ ME[25]; + out[10] = SE[get_byte(2, B2)] ^ ME[26]; + out[11] = SE[get_byte(2, B3)] ^ ME[27]; + out[12] = SE[get_byte(3, B0)] ^ ME[28]; + out[13] = SE[get_byte(3, B1)] ^ ME[29]; + out[14] = SE[get_byte(3, B2)] ^ ME[30]; + out[15] = SE[get_byte(3, B3)] ^ ME[31]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Square Decryption +*/ +void Square::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit B0, B1, B2, B3; + + B0 = TD0[in[ 0] ^ MD[ 0]] ^ TD1[in[ 4] ^ MD[ 4]] ^ + TD2[in[ 8] ^ MD[ 8]] ^ TD3[in[12] ^ MD[12]] ^ DK[0]; + B1 = TD0[in[ 1] ^ MD[ 1]] ^ TD1[in[ 5] ^ MD[ 5]] ^ + TD2[in[ 9] ^ MD[ 9]] ^ TD3[in[13] ^ MD[13]] ^ DK[1]; + B2 = TD0[in[ 2] ^ MD[ 2]] ^ TD1[in[ 6] ^ MD[ 6]] ^ + TD2[in[10] ^ MD[10]] ^ TD3[in[14] ^ MD[14]] ^ DK[2]; + B3 = TD0[in[ 3] ^ MD[ 3]] ^ TD1[in[ 7] ^ MD[ 7]] ^ + TD2[in[11] ^ MD[11]] ^ TD3[in[15] ^ MD[15]] ^ DK[3]; + + for(size_t j = 1; j != 7; j += 2) + { + u32bit T0, T1, T2, T3; + T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(0, B1)] ^ + TD2[get_byte(0, B2)] ^ TD3[get_byte(0, B3)] ^ DK[4*j+0]; + T1 = TD0[get_byte(1, B0)] ^ TD1[get_byte(1, B1)] ^ + TD2[get_byte(1, B2)] ^ TD3[get_byte(1, B3)] ^ DK[4*j+1]; + T2 = TD0[get_byte(2, B0)] ^ TD1[get_byte(2, B1)] ^ + TD2[get_byte(2, B2)] ^ TD3[get_byte(2, B3)] ^ DK[4*j+2]; + T3 = TD0[get_byte(3, B0)] ^ TD1[get_byte(3, B1)] ^ + TD2[get_byte(3, B2)] ^ TD3[get_byte(3, B3)] ^ DK[4*j+3]; + + B0 = TD0[get_byte(0, T0)] ^ TD1[get_byte(0, T1)] ^ + TD2[get_byte(0, T2)] ^ TD3[get_byte(0, T3)] ^ DK[4*j+4]; + B1 = TD0[get_byte(1, T0)] ^ TD1[get_byte(1, T1)] ^ + TD2[get_byte(1, T2)] ^ TD3[get_byte(1, T3)] ^ DK[4*j+5]; + B2 = TD0[get_byte(2, T0)] ^ TD1[get_byte(2, T1)] ^ + TD2[get_byte(2, T2)] ^ TD3[get_byte(2, T3)] ^ DK[4*j+6]; + B3 = TD0[get_byte(3, T0)] ^ TD1[get_byte(3, T1)] ^ + TD2[get_byte(3, T2)] ^ TD3[get_byte(3, T3)] ^ DK[4*j+7]; + } + + out[ 0] = SD[get_byte(0, B0)] ^ MD[16]; + out[ 1] = SD[get_byte(0, B1)] ^ MD[17]; + out[ 2] = SD[get_byte(0, B2)] ^ MD[18]; + out[ 3] = SD[get_byte(0, B3)] ^ MD[19]; + out[ 4] = SD[get_byte(1, B0)] ^ MD[20]; + out[ 5] = SD[get_byte(1, B1)] ^ MD[21]; + out[ 6] = SD[get_byte(1, B2)] ^ MD[22]; + out[ 7] = SD[get_byte(1, B3)] ^ MD[23]; + out[ 8] = SD[get_byte(2, B0)] ^ MD[24]; + out[ 9] = SD[get_byte(2, B1)] ^ MD[25]; + out[10] = SD[get_byte(2, B2)] ^ MD[26]; + out[11] = SD[get_byte(2, B3)] ^ MD[27]; + out[12] = SD[get_byte(3, B0)] ^ MD[28]; + out[13] = SD[get_byte(3, B1)] ^ MD[29]; + out[14] = SD[get_byte(3, B2)] ^ MD[30]; + out[15] = SD[get_byte(3, B3)] ^ MD[31]; + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Square Key Schedule +*/ +void Square::key_schedule(const byte key[], size_t) + { + SecureVector XEK(36), XDK(36); + + for(size_t i = 0; i != 4; ++i) + XEK[i] = load_be(key, i); + + for(size_t i = 0; i != 8; ++i) + { + XEK[4*i+4] = XEK[4*i ] ^ rotate_left(XEK[4*i+3], 8) ^ (0x01000000 << i); + XEK[4*i+5] = XEK[4*i+1] ^ XEK[4*i+4]; + XEK[4*i+6] = XEK[4*i+2] ^ XEK[4*i+5]; + XEK[4*i+7] = XEK[4*i+3] ^ XEK[4*i+6]; + + for(size_t j = 0; j != 4; ++j) + XDK[28 - 4*i + j] = XEK[4*(i+1)+j]; + + transform(&XEK[4*i]); + } + + for(size_t i = 0; i != 4; ++i) + for(size_t j = 0; j != 4; ++j) + { + ME[4*i+j ] = get_byte(j, XEK[i ]); + ME[4*i+j+16] = get_byte(j, XEK[i+32]); + MD[4*i+j ] = get_byte(j, XDK[i ]); + MD[4*i+j+16] = get_byte(j, XEK[i ]); + } + + EK.copy(&XEK[4], 28); + DK.copy(&XDK[4], 28); + } + +/* +* Square's Inverse Linear Transformation +*/ +void Square::transform(u32bit round_key[4]) + { + static const byte G[4][4] = { + { 2, 1, 1, 3 }, + { 3, 2, 1, 1 }, + { 1, 3, 2, 1 }, + { 1, 1, 3, 2 } }; + + for(size_t i = 0; i != 4; ++i) + { + byte A[4] = { 0 }, B[4] = { 0 }; + + store_be(round_key[i], A); + + for(size_t j = 0; j != 4; ++j) + for(size_t k = 0; k != 4; ++k) + { + const byte a = A[k]; + const byte b = G[k][j]; + + if(a && b) + B[j] ^= ALog[(Log[a] + Log[b]) % 255]; + } + + round_key[i] = load_be(B, 0); + } + } + +/* +* Clear memory of sensitive data +*/ +void Square::clear() + { + zeroise(EK); + zeroise(DK); + zeroise(ME); + zeroise(MD); + } + +} +/* +* TEA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* TEA Encryption +*/ +void TEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + u32bit S = 0; + for(size_t j = 0; j != 32; ++j) + { + S += 0x9E3779B9; + L += ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]); + R += ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]); + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TEA Decryption +*/ +void TEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + u32bit S = 0xC6EF3720; + for(size_t j = 0; j != 32; ++j) + { + R -= ((L << 4) + K[2]) ^ (L + S) ^ ((L >> 5) + K[3]); + L -= ((R << 4) + K[0]) ^ (R + S) ^ ((R >> 5) + K[1]); + S -= 0x9E3779B9; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* TEA Key Schedule +*/ +void TEA::key_schedule(const byte key[], size_t) + { + for(size_t i = 0; i != 4; ++i) + K[i] = load_be(key, i); + } + +} +/* +* S-Box and MDS Tables for Twofish +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const byte Twofish::Q0[256] = { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0 }; + +const byte Twofish::Q1[256] = { + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 }; + +const byte Twofish::RS[32] = { + 0x01, 0xA4, 0x02, 0xA4, 0xA4, 0x56, 0xA1, 0x55, 0x55, 0x82, 0xFC, 0x87, + 0x87, 0xF3, 0xC1, 0x5A, 0x5A, 0x1E, 0x47, 0x58, 0x58, 0xC6, 0xAE, 0xDB, + 0xDB, 0x68, 0x3D, 0x9E, 0x9E, 0xE5, 0x19, 0x03 }; + +const byte Twofish::EXP_TO_POLY[255] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2, + 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6, + 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A, + 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63, + 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C, + 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07, + 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88, + 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12, + 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7, + 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C, + 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8, + 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25, + 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A, + 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE, + 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC, + 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E, + 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92, + 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89, + 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB, + 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1, + 0x8F, 0x53, 0xA6 }; + +const byte Twofish::POLY_TO_EXP[255] = { + 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19, + 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A, + 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C, + 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B, + 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47, + 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D, + 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8, + 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C, + 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83, + 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48, + 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26, + 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E, + 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3, + 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9, + 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A, + 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D, + 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75, + 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84, + 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64, + 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49, + 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF, + 0x85, 0xC8, 0xA1 }; + +const u32bit Twofish::MDS0[256] = { + 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, + 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, + 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32, + 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, + 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, + 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, + 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1, + 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, + 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, + 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, + 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0, + 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, + 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, + 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, + 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3, + 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, + 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, + 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, + 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C, + 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, + 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, + 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, + 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72, + 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, + 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, + 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, + 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39, + 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, + 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, + 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, + 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5, + 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, + 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, + 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, + 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E, + 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, + 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, + 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, + 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2, + 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, + 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, + 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, + 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 }; + +const u32bit Twofish::MDS1[256] = { + 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, + 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, + 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020, + 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, + 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, + 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, + 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A, + 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, + 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, + 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, + 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9, + 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, + 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, + 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, + 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414, + 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, + 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, + 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, + 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5, + 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, + 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, + 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, + 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202, + 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, + 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, + 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, + 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808, + 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, + 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, + 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, + 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505, + 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, + 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, + 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, + 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF, + 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, + 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, + 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, + 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6, + 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, + 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, + 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, + 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 }; + +const u32bit Twofish::MDS2[256] = { + 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, + 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, + 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A, + 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, + 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, + 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, + 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB, + 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, + 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, + 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, + 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C, + 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, + 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, + 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, + 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035, + 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, + 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, + 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, + 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F, + 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, + 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, + 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, + 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA, + 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, + 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, + 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, + 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D, + 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, + 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, + 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, + 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086, + 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, + 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, + 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, + 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691, + 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, + 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, + 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, + 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E, + 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, + 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, + 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, + 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF }; + +const u32bit Twofish::MDS3[256] = { + 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, + 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, + 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643, + 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, + 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, + 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, + 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3, + 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, + 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, + 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, + 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF, + 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, + 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, + 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, + 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA, + 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, + 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, + 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, + 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D, + 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, + 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, + 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, + 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B, + 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, + 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, + 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, + 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE, + 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, + 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, + 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, + 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E, + 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, + 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, + 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, + 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718, + 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, + 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, + 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, + 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882, + 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, + 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, + 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, + 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 }; + +} +/* +* Twofish +* (C) 1999-2007 Jack Lloyd +* +* The key schedule implemenation is based on a public domain +* implementation by Matthew Skala +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Twofish Encryption +*/ +void Twofish::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) ^ RK[0]; + u32bit B = load_le(in, 1) ^ RK[1]; + u32bit C = load_le(in, 2) ^ RK[2]; + u32bit D = load_le(in, 3) ^ RK[3]; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit X, Y; + + X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + X += Y; + Y += X + RK[2*j + 9]; + X += RK[2*j + 8]; + + C = rotate_right(C ^ X, 1); + D = rotate_left(D, 1) ^ Y; + + X = SB[ get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^ + SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)]; + Y = SB[ get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^ + SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)]; + X += Y; + Y += X + RK[2*j + 11]; + X += RK[2*j + 10]; + + A = rotate_right(A ^ X, 1); + B = rotate_left(B, 1) ^ Y; + } + + C ^= RK[4]; + D ^= RK[5]; + A ^= RK[6]; + B ^= RK[7]; + + store_le(out, C, D, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Twofish Decryption +*/ +void Twofish::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + for(size_t i = 0; i != blocks; ++i) + { + u32bit A = load_le(in, 0) ^ RK[4]; + u32bit B = load_le(in, 1) ^ RK[5]; + u32bit C = load_le(in, 2) ^ RK[6]; + u32bit D = load_le(in, 3) ^ RK[7]; + + for(size_t j = 0; j != 16; j += 2) + { + u32bit X, Y; + + X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + X += Y; + Y += X + RK[39 - 2*j]; + X += RK[38 - 2*j]; + + C = rotate_left(C, 1) ^ X; + D = rotate_right(D ^ Y, 1); + + X = SB[ get_byte(3, C)] ^ SB[256+get_byte(2, C)] ^ + SB[512+get_byte(1, C)] ^ SB[768+get_byte(0, C)]; + Y = SB[ get_byte(0, D)] ^ SB[256+get_byte(3, D)] ^ + SB[512+get_byte(2, D)] ^ SB[768+get_byte(1, D)]; + X += Y; + Y += X + RK[37 - 2*j]; + X += RK[36 - 2*j]; + + A = rotate_left(A, 1) ^ X; + B = rotate_right(B ^ Y, 1); + } + + C ^= RK[0]; + D ^= RK[1]; + A ^= RK[2]; + B ^= RK[3]; + + store_le(out, C, D, A, B); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Twofish Key Schedule +*/ +void Twofish::key_schedule(const byte key[], size_t length) + { + SecureVector S(16); + + for(size_t i = 0; i != length; ++i) + rs_mul(&S[4*(i/8)], key[i], i); + + if(length == 16) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[i]^S[ 0]]^S[ 4]]; + SB[256+i] = MDS1[Q0[Q1[i]^S[ 1]]^S[ 5]]; + SB[512+i] = MDS2[Q1[Q0[i]^S[ 2]]^S[ 6]]; + SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[i ]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[i ]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[i ]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[i ]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[i+1]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[i+1]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[i+1]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[i+1]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + else if(length == 24) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]; + SB[256+i] = MDS1[Q0[Q1[Q1[i]^S[ 1]]^S[ 5]]^S[ 9]]; + SB[512+i] = MDS2[Q1[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]; + SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[Q1[i ]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[i ]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[i ]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[i ]^key[19]]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[Q1[i+1]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[i+1]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[i+1]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[i+1]^key[23]]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + else if(length == 32) + { + for(size_t i = 0; i != 256; ++i) + { + SB[ i] = MDS0[Q0[Q0[Q1[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]]; + SB[256+i] = MDS1[Q0[Q1[Q1[Q0[i]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]]; + SB[512+i] = MDS2[Q1[Q0[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]^S[14]]; + SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; + } + + for(size_t i = 0; i != 40; i += 2) + { + u32bit X = MDS0[Q0[Q0[Q1[Q1[i ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[Q0[i ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[Q0[i ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[Q1[i ]^key[27]]^key[19]]^key[11]]^key[ 3]]; + u32bit Y = MDS0[Q0[Q0[Q1[Q1[i+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[Q0[i+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[Q0[i+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[Q1[i+1]^key[31]]^key[23]]^key[15]]^key[ 7]]; + Y = rotate_left(Y, 8); + X += Y; Y += X; + + RK[i] = X; + RK[i+1] = rotate_left(Y, 9); + } + } + } + +/* +* Do one column of the RS matrix multiplcation +*/ +void Twofish::rs_mul(byte S[4], byte key, size_t offset) + { + if(key) + { + byte X = POLY_TO_EXP[key - 1]; + + byte RS1 = RS[(4*offset ) % 32]; + byte RS2 = RS[(4*offset+1) % 32]; + byte RS3 = RS[(4*offset+2) % 32]; + byte RS4 = RS[(4*offset+3) % 32]; + + S[0] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; + S[1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; + S[2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; + S[3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; + } + } + +/* +* Clear memory of sensitive data +*/ +void Twofish::clear() + { + zeroise(SB); + zeroise(RK); + } + +} +/* +* XTEA +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +void xtea_encrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) + { + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t i = 0; i != 32; ++i) + { + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i]; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i]; + L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i]; + L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i]; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1]; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1]; + R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1]; + R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1]; + } + + store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); + } + +void xtea_decrypt_4(const byte in[32], byte out[32], const u32bit EK[64]) + { + u32bit L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t i = 0; i != 32; ++i) + { + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i]; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i]; + R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i]; + R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i]; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i]; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i]; + L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i]; + L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i]; + } + + store_be(out, L0, R0, L1, R1, L2, R2, L3, R3); + } + +} + +/* +* XTEA Encryption +*/ +void XTEA::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + while(blocks >= 4) + { + xtea_encrypt_4(in, out, &(this->EK[0])); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 32; ++j) + { + L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*j]; + R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*j+1]; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* XTEA Decryption +*/ +void XTEA::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + while(blocks >= 4) + { + xtea_decrypt_4(in, out, &(this->EK[0])); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be(in, 0); + u32bit R = load_be(in, 1); + + for(size_t j = 0; j != 32; ++j) + { + R -= (((L << 4) ^ (L >> 5)) + L) ^ EK[63 - 2*j]; + L -= (((R << 4) ^ (R >> 5)) + R) ^ EK[62 - 2*j]; + } + + store_be(out, L, R); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* XTEA Key Schedule +*/ +void XTEA::key_schedule(const byte key[], size_t) + { + SecureVector UK(4); + for(size_t i = 0; i != 4; ++i) + UK[i] = load_be(key, i); + + u32bit D = 0; + for(size_t i = 0; i != 64; i += 2) + { + EK[i ] = D + UK[D % 4]; + D += 0x9E3779B9; + EK[i+1] = D + UK[(D >> 11) % 4]; + } + } + +} +/* +* XTEA in SIMD +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +void xtea_encrypt_8(const byte in[64], byte out[64], const u32bit EK[64]) + { + SIMD_32 L0 = SIMD_32::load_be(in ); + SIMD_32 R0 = SIMD_32::load_be(in + 16); + SIMD_32 L1 = SIMD_32::load_be(in + 32); + SIMD_32 R1 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(L0, R0, L1, R1); + + for(size_t i = 0; i != 32; i += 2) + { + SIMD_32 K0(EK[2*i ]); + SIMD_32 K1(EK[2*i+1]); + SIMD_32 K2(EK[2*i+2]); + SIMD_32 K3(EK[2*i+3]); + + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K0; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K0; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K1; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K1; + + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K2; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K2; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K3; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K3; + } + + SIMD_32::transpose(L0, R0, L1, R1); + + L0.store_be(out); + R0.store_be(out + 16); + L1.store_be(out + 32); + R1.store_be(out + 48); + } + +void xtea_decrypt_8(const byte in[64], byte out[64], const u32bit EK[64]) + { + SIMD_32 L0 = SIMD_32::load_be(in ); + SIMD_32 R0 = SIMD_32::load_be(in + 16); + SIMD_32 L1 = SIMD_32::load_be(in + 32); + SIMD_32 R1 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(L0, R0, L1, R1); + + for(size_t i = 0; i != 32; i += 2) + { + SIMD_32 K0(EK[63 - 2*i]); + SIMD_32 K1(EK[62 - 2*i]); + SIMD_32 K2(EK[61 - 2*i]); + SIMD_32 K3(EK[60 - 2*i]); + + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K0; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K0; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K1; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K1; + + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ K2; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ K2; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ K3; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ K3; + } + + SIMD_32::transpose(L0, R0, L1, R1); + + L0.store_be(out); + R0.store_be(out + 16); + L1.store_be(out + 32); + R1.store_be(out + 48); + } + +} + +/* +* XTEA Encryption +*/ +void XTEA_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_EK()[0]); + + while(blocks >= 8) + { + xtea_encrypt_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + XTEA::encrypt_n(in, out, blocks); + } + +/* +* XTEA Decryption +*/ +void XTEA_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* KS = &(this->get_EK()[0]); + + while(blocks >= 8) + { + xtea_decrypt_8(in, out, KS); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + + if(blocks) + XTEA::decrypt_n(in, out, blocks); + } + +} +/* +* Certificate Store +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +Certificate_Store* Certificate_Store_Memory::clone() const + { + return new Certificate_Store_Memory(*this); + } + +void Certificate_Store_Memory::add_certificate(const X509_Certificate& cert) + { + for(size_t i = 0; i != certs.size(); ++i) + { + if(certs[i] == cert) + return; + } + + certs.push_back(cert); + } + +std::vector +Certificate_Store_Memory::find_cert_by_subject_and_key_id( + const X509_DN& subject_dn, + const MemoryRegion& key_id) const + { + std::vector result; + + for(size_t i = 0; i != certs.size(); ++i) + { + // Only compare key ids if set in both call and in the cert + if(key_id.size()) + { + MemoryVector skid = certs[i].subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(certs[i].subject_dn() == subject_dn) + result.push_back(certs[i]); + } + + return result; + } + +void Certificate_Store_Memory::add_crl(const X509_CRL& crl) + { + X509_DN crl_issuer = crl.issuer_dn(); + + for(size_t i = 0; i != crls.size(); ++i) + { + // Found an update of a previously existing one; replace it + if(crls[i].issuer_dn() == crl_issuer) + { + if(crls[i].this_update() < crl.this_update()) + { + crls[i] = crl; + return; + } + } + } + + // Totally new CRL, add to the list + crls.push_back(crl); + } + +std::vector +Certificate_Store_Memory::find_crl_by_subject_and_key_id( + const X509_DN& issuer_dn, + const MemoryRegion& key_id) const + { + std::vector result; + + for(size_t i = 0; i != crls.size(); ++i) + { + // Only compare key ids if set in both call and in the CRL + if(key_id.size()) + { + MemoryVector akid = crls[i].authority_key_id(); + + if(akid.size() && akid != key_id) // no match + continue; + } + + if(crls[i].issuer_dn() == issuer_dn) + result.push_back(crls[i]); + } + + return result; + } + +} +/* +* PKCS #10 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* PKCS10_Request Constructor +*/ +PKCS10_Request::PKCS10_Request(DataSource& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + do_decode(); + } + +/* +* PKCS10_Request Constructor +*/ +PKCS10_Request::PKCS10_Request(const std::string& in) : + X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST") + { + do_decode(); + } + +/* +* Deocde the CertificateRequestInfo +*/ +void PKCS10_Request::force_decode() + { + BER_Decoder cert_req_info(tbs_bits); + + size_t version; + cert_req_info.decode(version); + if(version != 0) + throw Decoding_Error("Unknown version code in PKCS #10 request: " + + to_string(version)); + + X509_DN dn_subject; + cert_req_info.decode(dn_subject); + + info.add(dn_subject.contents()); + + BER_Object public_key = cert_req_info.get_next_object(); + if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", + public_key.type_tag, public_key.class_tag); + + info.add("X509.Certificate.public_key", + PEM_Code::encode( + ASN1::put_in_sequence(public_key.value), + "PUBLIC KEY" + ) + ); + + BER_Object attr_bits = cert_req_info.get_next_object(); + + if(attr_bits.type_tag == 0 && + attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + BER_Decoder attributes(attr_bits.value); + while(attributes.more_items()) + { + Attribute attr; + attributes.decode(attr); + handle_attribute(attr); + } + attributes.verify_end(); + } + else if(attr_bits.type_tag != NO_OBJECT) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", + attr_bits.type_tag, attr_bits.class_tag); + + cert_req_info.verify_end(); + + if(!this->check_signature(subject_public_key())) + throw Decoding_Error("PKCS #10 request: Bad signature detected"); + } + +/* +* Handle attributes in a PKCS #10 request +*/ +void PKCS10_Request::handle_attribute(const Attribute& attr) + { + BER_Decoder value(attr.parameters); + + if(attr.oid == OIDS::lookup("PKCS9.EmailAddress")) + { + ASN1_String email; + value.decode(email); + info.add("RFC822", email.value()); + } + else if(attr.oid == OIDS::lookup("PKCS9.ChallengePassword")) + { + ASN1_String challenge_password; + value.decode(challenge_password); + info.add("PKCS9.ChallengePassword", challenge_password.value()); + } + else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest")) + { + Extensions extensions; + value.decode(extensions).verify_end(); + + Data_Store issuer_info; + extensions.contents_to(info, issuer_info); + } + } + +/* +* Return the challenge password (if any) +*/ +std::string PKCS10_Request::challenge_password() const + { + return info.get1("PKCS9.ChallengePassword"); + } + +/* +* Return the name of the requestor +*/ +X509_DN PKCS10_Request::subject_dn() const + { + return create_dn(info); + } + +/* +* Return the public key of the requestor +*/ +MemoryVector PKCS10_Request::raw_public_key() const + { + DataSource_Memory source(info.get1("X509.Certificate.public_key")); + return PEM_Code::decode_check_label(source, "PUBLIC KEY"); + } + +/* +* Return the public key of the requestor +*/ +Public_Key* PKCS10_Request::subject_public_key() const + { + DataSource_Memory source(info.get1("X509.Certificate.public_key")); + return X509::load_key(source); + } + +/* +* Return the alternative names of the requestor +*/ +AlternativeName PKCS10_Request::subject_alt_name() const + { + return create_alt_name(info); + } + +/* +* Return the key constraints (if any) +*/ +Key_Constraints PKCS10_Request::constraints() const + { + return Key_Constraints(info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS)); + } + +/* +* Return the extendend key constraints (if any) +*/ +std::vector PKCS10_Request::ex_constraints() const + { + std::vector oids = info.get("X509v3.ExtendedKeyUsage"); + + std::vector result; + for(size_t i = 0; i != oids.size(); ++i) + result.push_back(OID(oids[i])); + return result; + } + +/* +* Return is a CA certificate is requested +*/ +bool PKCS10_Request::is_CA() const + { + return (info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0); + } + +/* +* Return the desired path limit (if any) +*/ +u32bit PKCS10_Request::path_limit() const + { + return info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + } + +} +/* +* X.509 Certificate Authority +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Load the certificate and private key +*/ +X509_CA::X509_CA(const X509_Certificate& c, + const Private_Key& key, + const std::string& hash_fn) : cert(c) + { + if(!cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + signer = choose_sig_format(key, hash_fn, ca_sig_algo); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + delete signer; + } + +/* +* Sign a PKCS #10 certificate request +*/ +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) + { + Key_Constraints constraints; + if(req.is_CA()) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + { + std::unique_ptr key(req.subject_public_key()); + constraints = X509::find_constraints(*key, req.constraints()); + } + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), + true); + + extensions.add(new Cert_Extension::Key_Usage(constraints), true); + + extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id())); + extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); + + extensions.add( + new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); + + extensions.add( + new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); + + return make_cert(signer, rng, ca_sig_algo, + req.raw_public_key(), + not_before, not_after, + cert.subject_dn(), req.subject_dn(), + extensions); + } + +/* +* Create a new certificate +*/ +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const MemoryRegion& 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) + { + const size_t X509_CERT_VERSION = 3; + const size_t SERIAL_BITS = 128; + + BigInt serial_no(rng, SERIAL_BITS); + + DataSource_Memory source(X509_Object::make_signed(signer, rng, sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .start_explicit(0) + .encode(X509_CERT_VERSION-1) + .end_explicit() + + .encode(serial_no) + + .encode(sig_algo) + .encode(issuer_dn) + + .start_cons(SEQUENCE) + .encode(not_before) + .encode(not_after) + .end_cons() + + .encode(subject_dn) + .raw_bytes(pub_key) + + .start_explicit(3) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents() + )); + + return X509_Certificate(source); + } + +/* +* Create a new, empty CRL +*/ +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + u32bit next_update) const + { + std::vector empty; + return make_crl(empty, 1, next_update, rng); + } + +/* +* Update a CRL with new entries +*/ +X509_CRL X509_CA::update_crl(const X509_CRL& crl, + const std::vector& new_revoked, + RandomNumberGenerator& rng, + u32bit next_update) const + { + std::vector revoked = crl.get_revoked(); + + std::copy(new_revoked.begin(), new_revoked.end(), + std::back_inserter(revoked)); + + return make_crl(revoked, crl.crl_number() + 1, next_update, rng); + } + +/* +* Create a CRL +*/ +X509_CRL X509_CA::make_crl(const std::vector& revoked, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const + { + const size_t X509_CRL_VERSION = 2; + + if(next_update == 0) + next_update = timespec_to_u32bit("7d"); + + // Totally stupid: ties encoding logic to the return of std::time!! + const u64bit current_time = system_time(); + + Extensions extensions; + extensions.add( + new Cert_Extension::Authority_Key_ID(cert.subject_key_id())); + extensions.add(new Cert_Extension::CRL_Number(crl_number)); + + DataSource_Memory source(X509_Object::make_signed(signer, rng, ca_sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .encode(X509_CRL_VERSION-1) + .encode(ca_sig_algo) + .encode(cert.issuer_dn()) + .encode(X509_Time(current_time)) + .encode(X509_Time(current_time + next_update)) + .encode_if(revoked.size() > 0, + DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(revoked) + .end_cons() + ) + .start_explicit(0) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents() + )); + + return X509_CRL(source); + } + +/* +* Return the CA's certificate +*/ +X509_Certificate X509_CA::ca_certificate() const + { + return cert; + } + +/* +* Choose a signing format for the key +*/ +PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + std::string padding; + + const std::string algo_name = key.algo_name(); + + const HashFunction* proto_hash = retrieve_hash(hash_fn); + if(!proto_hash) + throw Algorithm_Not_Found(hash_fn); + + if(key.max_input_bits() < proto_hash->output_length()*8) + throw Invalid_Argument("Key is too small for chosen hash function"); + + if(algo_name == "RSA") + padding = "EMSA3"; + else if(algo_name == "DSA") + padding = "EMSA1"; + else if(algo_name == "ECDSA") + padding = "EMSA1_BSI"; + else + throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + + Signature_Format format = + (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363; + + padding = padding + '(' + proto_hash->name() + ')'; + + sig_algo.oid = OIDS::lookup(algo_name + "/" + padding); + sig_algo.parameters = key.algorithm_identifier().parameters; + + return new PK_Signer(key, padding, format); + } + +} +/* +* X.509 Certificate Extensions +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* List of X.509 Certificate Extensions +*/ +Certificate_Extension* Extensions::get_extension(const OID& oid) + { +#define X509_EXTENSION(NAME, TYPE) \ + if(OIDS::name_of(oid, NAME)) \ + return new Cert_Extension::TYPE(); + + X509_EXTENSION("X509v3.KeyUsage", Key_Usage); + X509_EXTENSION("X509v3.BasicConstraints", Basic_Constraints); + X509_EXTENSION("X509v3.SubjectKeyIdentifier", Subject_Key_ID); + X509_EXTENSION("X509v3.AuthorityKeyIdentifier", Authority_Key_ID); + X509_EXTENSION("X509v3.ExtendedKeyUsage", Extended_Key_Usage); + X509_EXTENSION("X509v3.IssuerAlternativeName", Issuer_Alternative_Name); + X509_EXTENSION("X509v3.SubjectAlternativeName", Subject_Alternative_Name); + X509_EXTENSION("X509v3.CRLNumber", CRL_Number); + X509_EXTENSION("X509v3.CertificatePolicies", Certificate_Policies); + X509_EXTENSION("X509v3.ReasonCode", CRL_ReasonCode); + + return 0; + } + +/* +* Extensions Copy Constructor +*/ +Extensions::Extensions(const Extensions& extensions) : ASN1_Object() + { + *this = extensions; + } + +/* +* Extensions Assignment Operator +*/ +Extensions& Extensions::operator=(const Extensions& other) + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + extensions.clear(); + + for(size_t i = 0; i != other.extensions.size(); ++i) + extensions.push_back( + std::make_pair(other.extensions[i].first->copy(), + other.extensions[i].second)); + + return (*this); + } + +/* +* Return the OID of this extension +*/ +OID Certificate_Extension::oid_of() const + { + return OIDS::lookup(oid_name()); + } + +void Extensions::add(Certificate_Extension* extn, bool critical) + { + extensions.push_back(std::make_pair(extn, critical)); + } + +/* +* Encode an Extensions list +*/ +void Extensions::encode_into(DER_Encoder& to_object) const + { + for(size_t i = 0; i != extensions.size(); ++i) + { + const Certificate_Extension* ext = extensions[i].first; + const bool is_critical = extensions[i].second; + + const bool should_encode = ext->should_encode(); + + if(should_encode) + { + to_object.start_cons(SEQUENCE) + .encode(ext->oid_of()) + .encode_optional(is_critical, false) + .encode(ext->encode_inner(), OCTET_STRING) + .end_cons(); + } + } + } + +/* +* Decode a list of Extensions +*/ +void Extensions::decode_from(BER_Decoder& from_source) + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + extensions.clear(); + + BER_Decoder sequence = from_source.start_cons(SEQUENCE); + + while(sequence.more_items()) + { + OID oid; + MemoryVector value; + bool critical; + + sequence.start_cons(SEQUENCE) + .decode(oid) + .decode_optional(critical, BOOLEAN, UNIVERSAL, false) + .decode(value, OCTET_STRING) + .verify_end() + .end_cons(); + + Certificate_Extension* ext = get_extension(oid); + + if(!ext) + { + if(!critical || !should_throw) + continue; + + throw Decoding_Error("Encountered unknown X.509 extension marked " + "as critical; OID = " + oid.as_string()); + } + + ext->decode_inner(value); + + extensions.push_back(std::make_pair(ext, critical)); + } + sequence.verify_end(); + } + +/* +* Write the extensions to an info store +*/ +void Extensions::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + for(size_t i = 0; i != extensions.size(); ++i) + extensions[i].first->contents_to(subject_info, issuer_info); + } + +/* +* Delete an Extensions list +*/ +Extensions::~Extensions() + { + for(size_t i = 0; i != extensions.size(); ++i) + delete extensions[i].first; + } + +namespace Cert_Extension { + +/* +* Checked accessor for the path_limit member +*/ +size_t Basic_Constraints::get_path_limit() const + { + if(!is_ca) + throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); + return path_limit; + } + +/* +* Encode the extension +*/ +MemoryVector Basic_Constraints::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_if(is_ca, + DER_Encoder() + .encode(is_ca) + .encode_optional(path_limit, NO_CERT_PATH_LIMIT) + ) + .end_cons() + .get_contents(); + } + +/* +* Decode the extension +*/ +void Basic_Constraints::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional(is_ca, BOOLEAN, UNIVERSAL, false) + .decode_optional(path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) + .verify_end() + .end_cons(); + + if(is_ca == false) + path_limit = 0; + } + +/* +* Return a textual representation +*/ +void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.BasicConstraints.is_ca", (is_ca ? 1 : 0)); + subject.add("X509v3.BasicConstraints.path_constraint", path_limit); + } + +/* +* Encode the extension +*/ +MemoryVector Key_Usage::encode_inner() const + { + if(constraints == NO_CONSTRAINTS) + throw Encoding_Error("Cannot encode zero usage constraints"); + + const size_t unused_bits = low_bit(constraints) - 1; + + MemoryVector der; + der.push_back(BIT_STRING); + der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); + der.push_back(unused_bits % 8); + der.push_back((constraints >> 8) & 0xFF); + if(constraints & 0xFF) + der.push_back(constraints & 0xFF); + + return der; + } + +/* +* Decode the extension +*/ +void Key_Usage::decode_inner(const MemoryRegion& in) + { + BER_Decoder ber(in); + + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Bad tag for usage constraint", + obj.type_tag, obj.class_tag); + + if(obj.value.size() != 2 && obj.value.size() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]); + + u16bit usage = 0; + for(size_t i = 1; i != obj.value.size(); ++i) + usage = (obj.value[i] << 8) | usage; + + constraints = Key_Constraints(usage); + } + +/* +* Return a textual representation +*/ +void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.KeyUsage", constraints); + } + +/* +* Encode the extension +*/ +MemoryVector Subject_Key_ID::encode_inner() const + { + return DER_Encoder().encode(key_id, OCTET_STRING).get_contents(); + } + +/* +* Decode the extension +*/ +void Subject_Key_ID::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in).decode(key_id, OCTET_STRING).verify_end(); + } + +/* +* Return a textual representation +*/ +void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.SubjectKeyIdentifier", key_id); + } + +/* +* Subject_Key_ID Constructor +*/ +Subject_Key_ID::Subject_Key_ID(const MemoryRegion& pub_key) + { + SHA_160 hash; + key_id = hash.process(pub_key); + } + +/* +* Encode the extension +*/ +MemoryVector Authority_Key_ID::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) + .end_cons() + .get_contents(); + } + +/* +* Decode the extension +*/ +void Authority_Key_ID::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional_string(key_id, OCTET_STRING, 0); + } + +/* +* Return a textual representation +*/ +void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const + { + if(key_id.size()) + issuer.add("X509v3.AuthorityKeyIdentifier", key_id); + } + +/* +* Encode the extension +*/ +MemoryVector Alternative_Name::encode_inner() const + { + return DER_Encoder().encode(alt_name).get_contents(); + } + +/* +* Decode the extension +*/ +void Alternative_Name::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in).decode(alt_name); + } + +/* +* Return a textual representation +*/ +void Alternative_Name::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + std::multimap contents = + get_alt_name().contents(); + + if(oid_name_str == "X509v3.SubjectAlternativeName") + subject_info.add(contents); + else if(oid_name_str == "X509v3.IssuerAlternativeName") + issuer_info.add(contents); + else + throw Internal_Error("In Alternative_Name, unknown type " + + oid_name_str); + } + +/* +* Alternative_Name Constructor +*/ +Alternative_Name::Alternative_Name(const AlternativeName& alt_name, + const std::string& oid_name_str, + const std::string& config_name_str) + { + this->alt_name = alt_name; + this->oid_name_str = oid_name_str; + this->config_name_str = config_name_str; + } + +/* +* Subject_Alternative_Name Constructor +*/ +Subject_Alternative_Name::Subject_Alternative_Name( + const AlternativeName& name) : + + Alternative_Name(name, "X509v3.SubjectAlternativeName", + "subject_alternative_name") + { + } + +/* +* Issuer_Alternative_Name Constructor +*/ +Issuer_Alternative_Name::Issuer_Alternative_Name(const AlternativeName& name) : + Alternative_Name(name, "X509v3.IssuerAlternativeName", + "issuer_alternative_name") + { + } + +/* +* Encode the extension +*/ +MemoryVector Extended_Key_Usage::encode_inner() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(oids) + .end_cons() + .get_contents(); + } + +/* +* Decode the extension +*/ +void Extended_Key_Usage::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_list(oids) + .end_cons(); + } + +/* +* Return a textual representation +*/ +void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + for(size_t i = 0; i != oids.size(); ++i) + subject.add("X509v3.ExtendedKeyUsage", oids[i].as_string()); + } + +/* +* A policy specifier +*/ +class Policy_Information : public ASN1_Object + { + public: + OID oid; + + Policy_Information() {} + Policy_Information(const OID& oid) : oid(oid) {} + + void encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .end_cons(); + } + + void decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .discard_remaining() + .end_cons(); + } + }; + +/* +* Encode the extension +*/ +MemoryVector Certificate_Policies::encode_inner() const + { + std::vector policies; + + for(size_t i = 0; i != oids.size(); ++i) + policies.push_back(oids[i]); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(policies) + .end_cons() + .get_contents(); + } + +/* +* Decode the extension +*/ +void Certificate_Policies::decode_inner(const MemoryRegion& in) + { + std::vector policies; + + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_list(policies) + .end_cons(); + + oids.clear(); + for(size_t i = 0; i != policies.size(); ++i) + oids.push_back(policies[i].oid); + } + +/* +* Return a textual representation +*/ +void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const + { + for(size_t i = 0; i != oids.size(); ++i) + info.add("X509v3.ExtendedKeyUsage", oids[i].as_string()); + } + +/* +* Checked accessor for the crl_number member +*/ +size_t CRL_Number::get_crl_number() const + { + if(!has_value) + throw Invalid_State("CRL_Number::get_crl_number: Not set"); + return crl_number; + } + +/* +* Copy a CRL_Number extension +*/ +CRL_Number* CRL_Number::copy() const + { + if(!has_value) + throw Invalid_State("CRL_Number::copy: Not set"); + return new CRL_Number(crl_number); + } + +/* +* Encode the extension +*/ +MemoryVector CRL_Number::encode_inner() const + { + return DER_Encoder().encode(crl_number).get_contents(); + } + +/* +* Decode the extension +*/ +void CRL_Number::decode_inner(const MemoryRegion& in) + { + BER_Decoder(in).decode(crl_number); + } + +/* +* Return a textual representation +*/ +void CRL_Number::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLNumber", crl_number); + } + +/* +* Encode the extension +*/ +MemoryVector CRL_ReasonCode::encode_inner() const + { + return DER_Encoder() + .encode(static_cast(reason), ENUMERATED, UNIVERSAL) + .get_contents(); + } + +/* +* Decode the extension +*/ +void CRL_ReasonCode::decode_inner(const MemoryRegion& in) + { + size_t reason_code = 0; + BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); + reason = static_cast(reason_code); + } + +/* +* Return a textual representation +*/ +void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLReasonCode", reason); + } + +} + +} +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Create a generic X.509 object +*/ +X509_Object::X509_Object(DataSource& stream, const std::string& labels) + { + init(stream, labels); + } + +/* +* Createa a generic X.509 object +*/ +X509_Object::X509_Object(const std::string& file, const std::string& labels) + { + DataSource_Stream stream(file, true); + init(stream, labels); + } + +/* +* Read a PEM or BER X.509 object +*/ +void X509_Object::init(DataSource& in, const std::string& labels) + { + PEM_labels_allowed = split_on(labels, '/'); + if(PEM_labels_allowed.size() < 1) + throw Invalid_Argument("Bad labels argument to X509_Object"); + + PEM_label_pref = PEM_labels_allowed[0]; + std::sort(PEM_labels_allowed.begin(), PEM_labels_allowed.end()); + + try { + if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) + decode_info(in); + else + { + std::string got_label; + DataSource_Memory ber(PEM_Code::decode(in, got_label)); + + if(!std::binary_search(PEM_labels_allowed.begin(), + PEM_labels_allowed.end(), got_label)) + throw Decoding_Error("Invalid PEM label: " + got_label); + decode_info(ber); + } + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed: " + e.what()); + } + } + +/* +* Read a BER encoded X.509 object +*/ +void X509_Object::decode_info(DataSource& source) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .decode(sig_algo) + .decode(sig, BIT_STRING) + .verify_end() + .end_cons(); + } + +/* +* Return a BER or PEM encoded X.509 object +*/ +void X509_Object::encode(Pipe& out, X509_Encoding encoding) const + { + if(encoding == PEM) + out.write(this->PEM_encode()); + else + out.write(this->BER_encode()); + } + +/* +* Return a BER encoded X.509 object +*/ +MemoryVector X509_Object::BER_encode() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .encode(sig_algo) + .encode(sig, BIT_STRING) + .end_cons() + .get_contents(); + } + +/* +* Return a PEM encoded X.509 object +*/ +std::string X509_Object::PEM_encode() const + { + return PEM_Code::encode(BER_encode(), PEM_label_pref); + } + +/* +* Return the TBS data +*/ +MemoryVector X509_Object::tbs_data() const + { + return ASN1::put_in_sequence(tbs_bits); + } + +/* +* Return the signature of this object +*/ +MemoryVector X509_Object::signature() const + { + return sig; + } + +/* +* Return the algorithm used to sign this object +*/ +AlgorithmIdentifier X509_Object::signature_algorithm() const + { + return sig_algo; + } + +/* +* Return the hash used in generating the signature +*/ +std::string X509_Object::hash_used_for_signature() const + { + std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2) + throw Internal_Error("Invalid name format found for " + + sig_algo.oid.as_string()); + + std::vector pad_and_hash = + parse_algorithm_name(sig_info[1]); + + if(pad_and_hash.size() != 2) + throw Internal_Error("Invalid name format " + sig_info[1]); + + return pad_and_hash[1]; + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(Public_Key* pub_key) const + { + std::unique_ptr key(pub_key); + return check_signature(*key); + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(Public_Key& pub_key) const + { + try { + std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name()) + return false; + + std::string padding = sig_info[1]; + Signature_Format format = + (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + PK_Verifier verifier(pub_key, padding, format); + + return verifier.verify_message(tbs_data(), signature()); + } + catch(...) + { + return false; + } + } + +/* +* Apply the X.509 SIGNED macro +*/ +MemoryVector X509_Object::make_signed(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& algo, + const MemoryRegion& tbs_bits) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .encode(algo) + .encode(signer->sign_message(tbs_bits, rng), BIT_STRING) + .end_cons() + .get_contents(); + } + +/* +* Try to decode the actual information +*/ +void X509_Object::do_decode() + { + try { + force_decode(); + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed (" + + e.what() + ")"); + } + catch(Invalid_Argument& e) + { + throw Decoding_Error(PEM_label_pref + " decoding failed (" + + e.what() + ")"); + } + } + +} +/* +* X.509 Certificates +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Lookup each OID in the vector +*/ +std::vector lookup_oids(const std::vector& in) + { + std::vector out; + + std::vector::const_iterator i = in.begin(); + while(i != in.end()) + { + out.push_back(OIDS::lookup(OID(*i))); + ++i; + } + return out; + } + +} + +/* +* X509_Certificate Constructor +*/ +X509_Certificate::X509_Certificate(DataSource& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + self_signed = false; + do_decode(); + } + +/* +* X509_Certificate Constructor +*/ +X509_Certificate::X509_Certificate(const std::string& in) : + X509_Object(in, "CERTIFICATE/X509 CERTIFICATE") + { + self_signed = false; + do_decode(); + } + +/* +* Decode the TBSCertificate data +*/ +void X509_Certificate::force_decode() + { + size_t version; + BigInt serial_bn; + AlgorithmIdentifier sig_algo_inner; + X509_DN dn_issuer, dn_subject; + X509_Time start, end; + + BER_Decoder tbs_cert(tbs_bits); + + tbs_cert.decode_optional(version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + .decode(serial_bn) + .decode(sig_algo_inner) + .decode(dn_issuer) + .start_cons(SEQUENCE) + .decode(start) + .decode(end) + .verify_end() + .end_cons() + .decode(dn_subject); + + if(version > 2) + throw Decoding_Error("Unknown X.509 cert version " + Botan::to_string(version)); + if(sig_algo != sig_algo_inner) + throw Decoding_Error("Algorithm identifier mismatch"); + + self_signed = (dn_subject == dn_issuer); + + subject.add(dn_subject.contents()); + issuer.add(dn_issuer.contents()); + + BER_Object public_key = tbs_cert.get_next_object(); + if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) + throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key", + public_key.type_tag, public_key.class_tag); + + MemoryVector v2_issuer_key_id, v2_subject_key_id; + + tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1); + tbs_cert.decode_optional_string(v2_subject_key_id, BIT_STRING, 2); + + BER_Object v3_exts_data = tbs_cert.get_next_object(); + if(v3_exts_data.type_tag == 3 && + v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + Extensions extensions; + + BER_Decoder(v3_exts_data.value).decode(extensions).verify_end(); + + extensions.contents_to(subject, issuer); + } + else if(v3_exts_data.type_tag != NO_OBJECT) + throw BER_Bad_Tag("Unknown tag in X.509 cert", + v3_exts_data.type_tag, v3_exts_data.class_tag); + + if(tbs_cert.more_items()) + throw Decoding_Error("TBSCertificate has more items that expected"); + + subject.add("X509.Certificate.version", version); + subject.add("X509.Certificate.serial", BigInt::encode(serial_bn)); + subject.add("X509.Certificate.start", start.readable_string()); + subject.add("X509.Certificate.end", end.readable_string()); + + issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id); + subject.add("X509.Certificate.v2.key_id", v2_subject_key_id); + + subject.add("X509.Certificate.public_key", + PEM_Code::encode( + ASN1::put_in_sequence(public_key.value), + "PUBLIC KEY" + ) + ); + + if(is_CA_cert() && + !subject.has_value("X509v3.BasicConstraints.path_constraint")) + { + const size_t limit = (x509_version() < 3) ? + Cert_Extension::NO_CERT_PATH_LIMIT : 0; + + subject.add("X509v3.BasicConstraints.path_constraint", limit); + } + } + +/* +* Return the X.509 version in use +*/ +u32bit X509_Certificate::x509_version() const + { + return (subject.get1_u32bit("X509.Certificate.version") + 1); + } + +/* +* Return the time this cert becomes valid +*/ +std::string X509_Certificate::start_time() const + { + return subject.get1("X509.Certificate.start"); + } + +/* +* Return the time this cert becomes invalid +*/ +std::string X509_Certificate::end_time() const + { + return subject.get1("X509.Certificate.end"); + } + +/* +* Return information about the subject +*/ +std::vector +X509_Certificate::subject_info(const std::string& what) const + { + return subject.get(X509_DN::deref_info_field(what)); + } + +/* +* Return information about the issuer +*/ +std::vector +X509_Certificate::issuer_info(const std::string& what) const + { + return issuer.get(X509_DN::deref_info_field(what)); + } + +/* +* Return the public key in this certificate +*/ +Public_Key* X509_Certificate::subject_public_key() const + { + DataSource_Memory source(subject.get1("X509.Certificate.public_key")); + return X509::load_key(source); + } + +/* +* Check if the certificate is for a CA +*/ +bool X509_Certificate::is_CA_cert() const + { + if(!subject.get1_u32bit("X509v3.BasicConstraints.is_ca")) + return false; + if((constraints() & KEY_CERT_SIGN) || (constraints() == NO_CONSTRAINTS)) + return true; + return false; + } + +/* +* Return the path length constraint +*/ +u32bit X509_Certificate::path_limit() const + { + return subject.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + } + +/* +* Return the key usage constraints +*/ +Key_Constraints X509_Certificate::constraints() const + { + return Key_Constraints(subject.get1_u32bit("X509v3.KeyUsage", + NO_CONSTRAINTS)); + } + +/* +* Return the list of extended key usage OIDs +*/ +std::vector X509_Certificate::ex_constraints() const + { + return lookup_oids(subject.get("X509v3.ExtendedKeyUsage")); + } + +/* +* Return the list of certificate policies +*/ +std::vector X509_Certificate::policies() const + { + return lookup_oids(subject.get("X509v3.CertificatePolicies")); + } + +/* +* Return the authority key id +*/ +MemoryVector X509_Certificate::authority_key_id() const + { + return issuer.get1_memvec("X509v3.AuthorityKeyIdentifier"); + } + +/* +* Return the subject key id +*/ +MemoryVector X509_Certificate::subject_key_id() const + { + return subject.get1_memvec("X509v3.SubjectKeyIdentifier"); + } + +/* +* Return the certificate serial number +*/ +MemoryVector X509_Certificate::serial_number() const + { + return subject.get1_memvec("X509.Certificate.serial"); + } + +/* +* Return the distinguished name of the issuer +*/ +X509_DN X509_Certificate::issuer_dn() const + { + return create_dn(issuer); + } + +/* +* Return the distinguished name of the subject +*/ +X509_DN X509_Certificate::subject_dn() const + { + return create_dn(subject); + } + +/* +* Compare two certificates for equality +*/ +bool X509_Certificate::operator==(const X509_Certificate& other) const + { + return (sig == other.sig && + sig_algo == other.sig_algo && + self_signed == other.self_signed && + issuer == other.issuer && + subject == other.subject); + } + +/* +* X.509 Certificate Comparison +*/ +bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) + { + return !(cert1 == cert2); + } + +std::string X509_Certificate::to_string() const + { + const char* dn_fields[] = { "Name", + "Email", + "Organization", + "Organizational Unit", + "Locality", + "State", + "Country", + "IP", + "DNS", + "URI", + "PKIX.XMPPAddr", + 0 }; + + std::ostringstream out; + + for(size_t i = 0; dn_fields[i]; ++i) + { + const std::vector vals = this->subject_info(dn_fields[i]); + + if(vals.empty()) + continue; + + out << "Subject " << dn_fields[i] << ":"; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; + out << "\n"; + } + + for(size_t i = 0; dn_fields[i]; ++i) + { + const std::vector vals = this->issuer_info(dn_fields[i]); + + if(vals.empty()) + continue; + + out << "Issuer " << dn_fields[i] << ":"; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; + out << "\n"; + } + + out << "Version: " << this->x509_version() << "\n"; + + out << "Not valid before: " << this->start_time() << "\n"; + out << "Not valid after: " << this->end_time() << "\n"; + + out << "Constraints:\n"; + Key_Constraints constraints = this->constraints(); + if(constraints == NO_CONSTRAINTS) + out << " None\n"; + else + { + if(constraints & DIGITAL_SIGNATURE) + out << " Digital Signature\n"; + if(constraints & NON_REPUDIATION) + out << " Non-Repuidation\n"; + if(constraints & KEY_ENCIPHERMENT) + out << " Key Encipherment\n"; + if(constraints & DATA_ENCIPHERMENT) + out << " Data Encipherment\n"; + if(constraints & KEY_AGREEMENT) + out << " Key Agreement\n"; + if(constraints & KEY_CERT_SIGN) + out << " Cert Sign\n"; + if(constraints & CRL_SIGN) + out << " CRL Sign\n"; + } + + std::vector policies = this->policies(); + if(policies.size()) + { + out << "Policies: " << "\n"; + for(size_t i = 0; i != policies.size(); i++) + out << " " << policies[i] << "\n"; + } + + std::vector ex_constraints = this->ex_constraints(); + if(ex_constraints.size()) + { + out << "Extended Constraints:\n"; + for(size_t i = 0; i != ex_constraints.size(); i++) + out << " " << ex_constraints[i] << "\n"; + } + + out << "Signature algorithm: " << + OIDS::lookup(this->signature_algorithm().oid) << "\n"; + + out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; + + if(this->authority_key_id().size()) + out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; + + if(this->subject_key_id().size()) + out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; + + X509_PublicKey* pubkey = this->subject_public_key(); + out << "Public Key:\n" << X509::PEM_encode(*pubkey); + delete pubkey; + + return out.str(); + } + +/* +* Create and populate a X509_DN +*/ +X509_DN create_dn(const Data_Store& info) + { + class DN_Matcher : public Data_Store::Matcher + { + public: + bool operator()(const std::string& key, const std::string&) const + { + if(key.find("X520.") != std::string::npos) + return true; + return false; + } + }; + + std::multimap names = + info.search_with(DN_Matcher()); + + X509_DN dn; + + std::multimap::iterator i; + for(i = names.begin(); i != names.end(); ++i) + dn.add_attribute(i->first, i->second); + + return dn; + } + +/* +* Create and populate an AlternativeName +*/ +AlternativeName create_alt_name(const Data_Store& info) + { + class AltName_Matcher : public Data_Store::Matcher + { + public: + bool operator()(const std::string& key, const std::string&) const + { + for(size_t i = 0; i != matches.size(); ++i) + if(key.compare(matches[i]) == 0) + return true; + return false; + } + + AltName_Matcher(const std::string& match_any_of) + { + matches = split_on(match_any_of, '/'); + } + private: + std::vector matches; + }; + + std::multimap names = + info.search_with(AltName_Matcher("RFC822/DNS/URI/IP")); + + AlternativeName alt_name; + + std::multimap::iterator i; + for(i = names.begin(); i != names.end(); ++i) + alt_name.add_attribute(i->first, i->second); + + return alt_name; + } + +} +/* +* CRL Entry +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(bool t_on_unknown_crit) : + throw_on_unknown_critical(t_on_unknown_crit) + { + reason = UNSPECIFIED; + } + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) : + throw_on_unknown_critical(false) + { + serial = cert.serial_number(); + time = X509_Time(system_time()); + reason = why; + } + +/* +* Compare two CRL_Entrys for equality +*/ +bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) + { + if(a1.serial_number() != a2.serial_number()) + return false; + if(a1.expire_time() != a2.expire_time()) + return false; + if(a1.reason_code() != a2.reason_code()) + return false; + return true; + } + +/* +* Compare two CRL_Entrys for inequality +*/ +bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) + { + return !(a1 == a2); + } + +/* +* DER encode a CRL_Entry +*/ +void CRL_Entry::encode_into(DER_Encoder& der) const + { + Extensions extensions; + + extensions.add(new Cert_Extension::CRL_ReasonCode(reason)); + + der.start_cons(SEQUENCE) + .encode(BigInt::decode(serial)) + .encode(time) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded CRL_Entry +*/ +void CRL_Entry::decode_from(BER_Decoder& source) + { + BigInt serial_number_bn; + reason = UNSPECIFIED; + + BER_Decoder entry = source.start_cons(SEQUENCE); + + entry.decode(serial_number_bn).decode(time); + + if(entry.more_items()) + { + Extensions extensions(throw_on_unknown_critical); + entry.decode(extensions); + Data_Store info; + extensions.contents_to(info, info); + reason = CRL_Code(info.get1_u32bit("X509v3.CRLReasonCode")); + } + + entry.end_cons(); + + serial = BigInt::encode(serial_number_bn); + } + +} +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Load a X.509 CRL +*/ +X509_CRL::X509_CRL(DataSource& in, bool touc) : + X509_Object(in, "X509 CRL/CRL"), throw_on_unknown_critical(touc) + { + do_decode(); + } + +/* +* Load a X.509 CRL +*/ +X509_CRL::X509_CRL(const std::string& in, bool touc) : + X509_Object(in, "CRL/X509 CRL"), throw_on_unknown_critical(touc) + { + do_decode(); + } + +/* +* Decode the TBSCertList data +*/ +void X509_CRL::force_decode() + { + BER_Decoder tbs_crl(tbs_bits); + + size_t version; + tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); + + if(version != 0 && version != 1) + throw X509_CRL_Error("Unknown X.509 CRL version " + + to_string(version+1)); + + AlgorithmIdentifier sig_algo_inner; + tbs_crl.decode(sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw X509_CRL_Error("Algorithm identifier mismatch"); + + X509_DN dn_issuer; + tbs_crl.decode(dn_issuer); + info.add(dn_issuer.contents()); + + X509_Time start, end; + tbs_crl.decode(start).decode(end); + info.add("X509.CRL.start", start.readable_string()); + info.add("X509.CRL.end", end.readable_string()); + + BER_Object next = tbs_crl.get_next_object(); + + if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED) + { + BER_Decoder cert_list(next.value); + + while(cert_list.more_items()) + { + CRL_Entry entry(throw_on_unknown_critical); + cert_list.decode(entry); + revoked.push_back(entry); + } + next = tbs_crl.get_next_object(); + } + + if(next.type_tag == 0 && + next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + { + BER_Decoder crl_options(next.value); + + Extensions extensions(throw_on_unknown_critical); + + crl_options.decode(extensions).verify_end(); + + extensions.contents_to(info, info); + + next = tbs_crl.get_next_object(); + } + + if(next.type_tag != NO_OBJECT) + throw X509_CRL_Error("Unknown tag in CRL"); + + tbs_crl.verify_end(); + } + +/* +* Return the list of revoked certificates +*/ +std::vector X509_CRL::get_revoked() const + { + return revoked; + } + +/* +* Return the distinguished name of the issuer +*/ +X509_DN X509_CRL::issuer_dn() const + { + return create_dn(info); + } + +/* +* Return the key identifier of the issuer +*/ +MemoryVector X509_CRL::authority_key_id() const + { + return info.get1_memvec("X509v3.AuthorityKeyIdentifier"); + } + +/* +* Return the CRL number of this CRL +*/ +u32bit X509_CRL::crl_number() const + { + return info.get1_u32bit("X509v3.CRLNumber"); + } + +/* +* Return the issue data of the CRL +*/ +X509_Time X509_CRL::this_update() const + { + return info.get1("X509.CRL.start"); + } + +/* +* Return the date when a new CRL will be issued +*/ +X509_Time X509_CRL::next_update() const + { + return info.get1("X509.CRL.end"); + } + +} +/* +* X.509 Certificate Options +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Set when the certificate should become valid +*/ +void X509_Cert_Options::not_before(const std::string& time_string) + { + start = X509_Time(time_string); + } + +/* +* Set when the certificate should expire +*/ +void X509_Cert_Options::not_after(const std::string& time_string) + { + end = X509_Time(time_string); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_constraints(Key_Constraints usage) + { + constraints = usage; + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const OID& oid) + { + ex_constraints.push_back(oid); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) + { + ex_constraints.push_back(OIDS::lookup(oid_str)); + } + +/* +* Mark this certificate for CA usage +*/ +void X509_Cert_Options::CA_key(size_t limit) + { + is_CA = true; + path_limit = limit; + } + +/* +* Do basic sanity checks +*/ +void X509_Cert_Options::sanity_check() const + { + if(common_name == "" || country == "") + throw Encoding_Error("X.509 certificate: name and country MUST be set"); + if(country.size() != 2) + throw Encoding_Error("Invalid ISO country code: " + country); + if(start >= end) + throw Encoding_Error("X509_Cert_Options: invalid time constraints"); + } + +/* +* Initialize the certificate options +*/ +X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, + u32bit expiration_time_in_seconds) + { + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + + const u64bit now = system_time(); + + start = X509_Time(now); + end = X509_Time(now + expiration_time_in_seconds); + + if(initial_opts == "") + return; + + std::vector parsed = split_on(initial_opts, '/'); + + if(parsed.size() > 4) + throw Invalid_Argument("X.509 cert options: Too many names: " + + initial_opts); + + if(parsed.size() >= 1) common_name = parsed[0]; + if(parsed.size() >= 2) country = parsed[1]; + if(parsed.size() >= 3) organization = parsed[2]; + if(parsed.size() == 4) org_unit = parsed[3]; + } + +} +/* +* PKCS #10/Self Signed Cert Creation +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* Load information from the X509_Cert_Options +*/ +void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, + AlternativeName& subject_alt) + { + subject_dn.add_attribute("X520.CommonName", opts.common_name); + subject_dn.add_attribute("X520.Country", opts.country); + subject_dn.add_attribute("X520.State", opts.state); + subject_dn.add_attribute("X520.Locality", opts.locality); + subject_dn.add_attribute("X520.Organization", opts.organization); + subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); + subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); + subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); + subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"), + opts.xmpp, UTF8_STRING); + } + +} + +namespace X509 { + +/* +* Create a new self-signed X.509 certificate +*/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + MemoryVector pub_key = X509::BER_encode(key); + std::unique_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + Key_Constraints constraints; + if(opts.is_CA) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + constraints = find_constraints(key, opts.constraints); + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), + true); + + extensions.add(new Cert_Extension::Key_Usage(constraints), true); + + extensions.add(new Cert_Extension::Subject_Key_ID(pub_key)); + + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + + return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, + opts.start, opts.end, + subject_dn, subject_dn, + extensions); + } + +/* +* Create a PKCS #10 certificate request +*/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + MemoryVector pub_key = X509::BER_encode(key); + std::unique_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + const size_t PKCS10_VERSION = 0; + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + extensions.add( + new Cert_Extension::Key_Usage( + opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) : + find_constraints(key, opts.constraints) + ) + ); + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + DER_Encoder tbs_req; + + tbs_req.start_cons(SEQUENCE) + .encode(PKCS10_VERSION) + .encode(subject_dn) + .raw_bytes(pub_key) + .start_explicit(0); + + if(opts.challenge != "") + { + ASN1_String challenge(opts.challenge, DIRECTORY_STRING); + + tbs_req.encode( + Attribute("PKCS9.ChallengePassword", + DER_Encoder().encode(challenge).get_contents() + ) + ); + } + + tbs_req.encode( + Attribute("PKCS9.ExtensionRequest", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .get_contents() + ) + ) + .end_explicit() + .end_cons(); + + DataSource_Memory source( + X509_Object::make_signed(signer.get(), + rng, + sig_algo, + tbs_req.get_contents()) + ); + + return PKCS10_Request(source); + } + +} + +} +/* +* X.509 Certificate Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Do a validity check +*/ +s32bit validity_check(const X509_Time& start, const X509_Time& end, + u64bit current_time, u32bit slack) + { + const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1; + + if(start.cmp(current_time + slack) > 0) + return NOT_YET_VALID; + if(end.cmp(current_time - slack) < 0) + return EXPIRED; + return VALID_TIME; + } + +/* +* Compare the value of unique ID fields +*/ +bool compare_ids(const MemoryVector& id1, + const MemoryVector& id2) + { + if(!id1.size() || !id2.size()) + return true; + return (id1 == id2); + } + +/* +* Check a particular usage restriction +*/ +bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage, + X509_Store::Cert_Usage check_for, Key_Constraints constraints) + { + if((usage & check_for) == 0) + return true; + if(cert.constraints() == NO_CONSTRAINTS) + return true; + if(cert.constraints() & constraints) + return true; + return false; + } + +/* +* Check a particular usage restriction +*/ +bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage, + X509_Store::Cert_Usage check_for, + const std::string& usage_oid) + { + if((usage & check_for) == 0) + return true; + + const std::vector constraints = cert.ex_constraints(); + + if(constraints.empty()) + return true; + + return std::binary_search(constraints.begin(), constraints.end(), + usage_oid); + } + +/* +* Check the usage restrictions +*/ +X509_Code usage_check(const X509_Certificate& cert, + X509_Store::Cert_Usage usage) + { + if(usage == X509_Store::ANY) + return VERIFIED; + + if(!check_usage(cert, usage, X509_Store::CRL_SIGNING, CRL_SIGN)) + return CA_CERT_NOT_FOR_CRL_ISSUER; + + if(!check_usage(cert, usage, X509_Store::TLS_SERVER, "PKIX.ServerAuth")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::TLS_CLIENT, "PKIX.ClientAuth")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::CODE_SIGNING, "PKIX.CodeSigning")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::EMAIL_PROTECTION, + "PKIX.EmailProtection")) + return INVALID_USAGE; + if(!check_usage(cert, usage, X509_Store::TIME_STAMPING, + "PKIX.TimeStamping")) + return INVALID_USAGE; + + return VERIFIED; + } + +} + +/* +* Define equality for revocation data +*/ +bool X509_Store::CRL_Data::operator==(const CRL_Data& other) const + { + if(issuer != other.issuer) + return false; + if(serial != other.serial) + return false; + return compare_ids(auth_key_id, other.auth_key_id); + } + +/* +* Define inequality for revocation data +*/ +bool X509_Store::CRL_Data::operator!=(const CRL_Data& other) const + { + return !((*this) == other); + } + +/* +* Define an ordering for revocation data +*/ +bool X509_Store::CRL_Data::operator<(const X509_Store::CRL_Data& other) const + { + if(*this == other) + return false; + + const MemoryVector& serial1 = serial; + const MemoryVector& key_id1 = auth_key_id; + const MemoryVector& serial2 = other.serial; + const MemoryVector& key_id2 = other.auth_key_id; + + if(compare_ids(key_id1, key_id2) == false) + { + if(std::lexicographical_compare(key_id1.begin(), key_id1.end(), + key_id2.begin(), key_id2.end())) + return true; + + if(std::lexicographical_compare(key_id2.begin(), key_id2.end(), + key_id1.begin(), key_id1.end())) + return false; + } + + if(compare_ids(serial1, serial2) == false) + { + if(std::lexicographical_compare(serial1.begin(), serial1.end(), + serial2.begin(), serial2.end())) + return true; + + if(std::lexicographical_compare(serial2.begin(), serial2.end(), + serial1.begin(), serial1.end())) + return false; + } + + return (issuer < other.issuer); + } + +/* +* X509_Store Constructor +*/ +X509_Store::X509_Store(u32bit slack, u32bit cache_timeout) + { + revoked_info_valid = true; + + validation_cache_timeout = cache_timeout; + time_slack = slack; + } + +/* +* X509_Store Copy Constructor +*/ +X509_Store::X509_Store(const X509_Store& other) + { + certs = other.certs; + revoked = other.revoked; + revoked_info_valid = other.revoked_info_valid; + for(size_t j = 0; j != other.stores.size(); ++j) + stores[j] = other.stores[j]->clone(); + time_slack = other.time_slack; + } + +/* +* X509_Store Destructor +*/ +X509_Store::~X509_Store() + { + for(size_t j = 0; j != stores.size(); ++j) + delete stores[j]; + } + +/* +* Verify a certificate's authenticity +*/ +X509_Code X509_Store::validate_cert(const X509_Certificate& cert, + Cert_Usage cert_usage) + { + recompute_revoked_info(); + + std::vector indexes; + X509_Code chaining_result = construct_cert_chain(cert, indexes); + if(chaining_result != VERIFIED) + return chaining_result; + + const u64bit current_time = system_time(); + + s32bit time_check = validity_check(cert.start_time(), cert.end_time(), + current_time, time_slack); + if(time_check < 0) return CERT_NOT_YET_VALID; + else if(time_check > 0) return CERT_HAS_EXPIRED; + + X509_Code sig_check_result = check_sig(cert, certs[indexes[0]]); + if(sig_check_result != VERIFIED) + return sig_check_result; + + if(is_revoked(cert)) + return CERT_IS_REVOKED; + + for(size_t j = 0; j != indexes.size() - 1; ++j) + { + const X509_Certificate& current_cert = certs[indexes[j]].cert; + + time_check = validity_check(current_cert.start_time(), + current_cert.end_time(), + current_time, + time_slack); + + if(time_check < 0) return CERT_NOT_YET_VALID; + else if(time_check > 0) return CERT_HAS_EXPIRED; + + sig_check_result = check_sig(certs[indexes[j]], certs[indexes[j+1]]); + if(sig_check_result != VERIFIED) + return sig_check_result; + } + + return usage_check(cert, cert_usage); + } + +/* +* Find this certificate +*/ +size_t X509_Store::find_cert(const X509_DN& subject_dn, + const MemoryRegion& subject_key_id) const + { + for(size_t j = 0; j != certs.size(); ++j) + { + const X509_Certificate& this_cert = certs[j].cert; + if(compare_ids(this_cert.subject_key_id(), subject_key_id) && + this_cert.subject_dn() == subject_dn) + return j; + } + return NO_CERT_FOUND; + } + +/* +* Find the parent of this certificate +*/ +size_t X509_Store::find_parent_of(const X509_Certificate& cert) + { + const X509_DN issuer_dn = cert.issuer_dn(); + const MemoryVector auth_key_id = cert.authority_key_id(); + + size_t index = find_cert(issuer_dn, auth_key_id); + + if(index != NO_CERT_FOUND) + return index; + + for(size_t j = 0; j != stores.size(); ++j) + { + std::vector got = + stores[j]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id); + + for(size_t k = 0; k != got.size(); ++k) + add_cert(got[k]); + } + + return find_cert(issuer_dn, auth_key_id); + } + +/* +* Construct a chain of certificate relationships +*/ +X509_Code X509_Store::construct_cert_chain(const X509_Certificate& end_cert, + std::vector& indexes, + bool need_full_chain) + { + size_t parent = find_parent_of(end_cert); + + while(true) + { + if(parent == NO_CERT_FOUND) + return CERT_ISSUER_NOT_FOUND; + indexes.push_back(parent); + + if(certs[parent].is_verified(validation_cache_timeout)) + if(certs[parent].verify_result() != VERIFIED) + return certs[parent].verify_result(); + + const X509_Certificate& parent_cert = certs[parent].cert; + if(!parent_cert.is_CA_cert()) + return CA_CERT_NOT_FOR_CERT_ISSUER; + + if(certs[parent].is_trusted()) + break; + if(parent_cert.is_self_signed()) + return CANNOT_ESTABLISH_TRUST; + + if(parent_cert.path_limit() < indexes.size() - 1) + return CERT_CHAIN_TOO_LONG; + + parent = find_parent_of(parent_cert); + } + + if(need_full_chain) + return VERIFIED; + + while(true) + { + if(indexes.size() < 2) + break; + + const size_t cert = indexes.back(); + + if(certs[cert].is_verified(validation_cache_timeout)) + { + if(certs[cert].verify_result() != VERIFIED) + throw Internal_Error("X509_Store::construct_cert_chain"); + indexes.pop_back(); + } + else + break; + } + + const size_t last_cert = indexes.back(); + const size_t parent_of_last_cert = find_parent_of(certs[last_cert].cert); + if(parent_of_last_cert == NO_CERT_FOUND) + return CERT_ISSUER_NOT_FOUND; + indexes.push_back(parent_of_last_cert); + + return VERIFIED; + } + +/* +* Check the CAs signature on a certificate +*/ +X509_Code X509_Store::check_sig(const Cert_Info& cert_info, + const Cert_Info& ca_cert_info) const + { + if(cert_info.is_verified(validation_cache_timeout)) + return cert_info.verify_result(); + + const X509_Certificate& cert = cert_info.cert; + const X509_Certificate& ca_cert = ca_cert_info.cert; + + X509_Code verify_code = check_sig(cert, ca_cert.subject_public_key()); + + cert_info.set_result(verify_code); + + return verify_code; + } + +/* +* Check a CA's signature +*/ +X509_Code X509_Store::check_sig(const X509_Object& object, Public_Key* key) + { + std::unique_ptr pub_key(key); + + try { + std::vector sig_info = + split_on(OIDS::lookup(object.signature_algorithm().oid), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + return SIGNATURE_ERROR; + + std::string padding = sig_info[1]; + Signature_Format format; + if(key->message_parts() >= 2) format = DER_SEQUENCE; + else format = IEEE_1363; + + PK_Verifier verifier(*pub_key.get(), padding, format); + + bool valid = verifier.verify_message(object.tbs_data(), + object.signature()); + + if(valid) + return VERIFIED; + else + return SIGNATURE_ERROR; + } + catch(Lookup_Error) { return CA_CERT_CANNOT_SIGN; } + catch(Decoding_Error) { return CERT_FORMAT_ERROR; } + catch(Exception) {} + + return UNKNOWN_X509_ERROR; + } + +/* +* Recompute the revocation status of the certs +*/ +void X509_Store::recompute_revoked_info() const + { + if(revoked_info_valid) + return; + + for(size_t j = 0; j != certs.size(); ++j) + { + if((certs[j].is_verified(validation_cache_timeout)) && + (certs[j].verify_result() != VERIFIED)) + continue; + + if(is_revoked(certs[j].cert)) + certs[j].set_result(CERT_IS_REVOKED); + } + + revoked_info_valid = true; + } + +/* +* Check if a certificate is revoked +*/ +bool X509_Store::is_revoked(const X509_Certificate& cert) const + { + CRL_Data revoked_info; + revoked_info.issuer = cert.issuer_dn(); + revoked_info.serial = cert.serial_number(); + revoked_info.auth_key_id = cert.authority_key_id(); + + if(std::binary_search(revoked.begin(), revoked.end(), revoked_info)) + return true; + return false; + } + +/* +* Construct a path back to a root for this cert +*/ +std::vector +X509_Store::get_cert_chain(const X509_Certificate& cert) + { + std::vector result; + std::vector indexes; + X509_Code chaining_result = construct_cert_chain(cert, indexes, true); + + if(chaining_result != VERIFIED) + throw Invalid_State("X509_Store::get_cert_chain: Can't construct chain"); + + for(size_t j = 0; j != indexes.size(); ++j) + result.push_back(certs[indexes[j]].cert); + return result; + } + +/* +* Add a certificate store to the list of stores +*/ +void X509_Store::add_new_certstore(Certificate_Store* certstore) + { + stores.push_back(certstore); + } + +/* +* Add a certificate to the store +*/ +void X509_Store::add_cert(const X509_Certificate& cert, bool trusted) + { + if(trusted && !cert.is_self_signed()) + throw Invalid_Argument("X509_Store: Trusted certs must be self-signed"); + + if(find_cert(cert.subject_dn(), cert.subject_key_id()) == NO_CERT_FOUND) + { + revoked_info_valid = false; + Cert_Info info(cert, trusted); + certs.push_back(info); + } + else if(trusted) + { + for(size_t j = 0; j != certs.size(); ++j) + { + const X509_Certificate& this_cert = certs[j].cert; + if(this_cert == cert) + certs[j].trusted = trusted; + } + } + } + +/* +* Add one or more certificates to the store +*/ +void X509_Store::do_add_certs(DataSource& source, bool trusted) + { + while(!source.end_of_data()) + { + try { + X509_Certificate cert(source); + add_cert(cert, trusted); + } + catch(Decoding_Error) {} + catch(Invalid_Argument) {} + } + } + +/* +* Add one or more certificates to the store +*/ +void X509_Store::add_certs(DataSource& source) + { + do_add_certs(source, false); + } + +/* +* Add one or more certificates to the store +*/ +void X509_Store::add_trusted_certs(DataSource& source) + { + do_add_certs(source, true); + } + +/* +* Add one or more certificates to the store +*/ +X509_Code X509_Store::add_crl(const X509_CRL& crl) + { + s32bit time_check = validity_check(crl.this_update(), crl.next_update(), + system_time(), time_slack); + + if(time_check < 0) return CRL_NOT_YET_VALID; + else if(time_check > 0) return CRL_HAS_EXPIRED; + + size_t cert_index = NO_CERT_FOUND; + + for(size_t j = 0; j != certs.size(); ++j) + { + const X509_Certificate& this_cert = certs[j].cert; + if(compare_ids(this_cert.subject_key_id(), crl.authority_key_id())) + { + if(this_cert.subject_dn() == crl.issuer_dn()) + cert_index = j; + } + } + + if(cert_index == NO_CERT_FOUND) + return CRL_ISSUER_NOT_FOUND; + + const X509_Certificate& ca_cert = certs[cert_index].cert; + + X509_Code verify_result = validate_cert(ca_cert, CRL_SIGNING); + if(verify_result != VERIFIED) + return verify_result; + + verify_result = check_sig(crl, ca_cert.subject_public_key()); + if(verify_result != VERIFIED) + return verify_result; + + std::vector revoked_certs = crl.get_revoked(); + + for(size_t j = 0; j != revoked_certs.size(); ++j) + { + CRL_Data revoked_info; + revoked_info.issuer = crl.issuer_dn(); + revoked_info.serial = revoked_certs[j].serial_number(); + revoked_info.auth_key_id = crl.authority_key_id(); + + std::vector::iterator p = + std::find(revoked.begin(), revoked.end(), revoked_info); + + if(revoked_certs[j].reason_code() == REMOVE_FROM_CRL) + { + if(p == revoked.end()) continue; + revoked.erase(p); + } + else + { + if(p != revoked.end()) continue; + revoked.push_back(revoked_info); + } + } + + std::sort(revoked.begin(), revoked.end()); + revoked_info_valid = false; + + return VERIFIED; + } + +/* +* PEM encode the set of certificates +*/ +std::string X509_Store::PEM_encode() const + { + std::string cert_store; + for(size_t j = 0; j != certs.size(); ++j) + cert_store += certs[j].cert.PEM_encode(); + return cert_store; + } + +/* +* Create a Cert_Info structure +*/ +X509_Store::Cert_Info::Cert_Info(const X509_Certificate& c, + bool t) : cert(c), trusted(t) + { + checked = false; + result = UNKNOWN_X509_ERROR; + last_checked = 0; + } + +/* +* Return the verification results +*/ +X509_Code X509_Store::Cert_Info::verify_result() const + { + if(!checked) + throw Invalid_State("Cert_Info::verify_result() called; not checked"); + return result; + } + +/* +* Set the verification results +*/ +void X509_Store::Cert_Info::set_result(X509_Code code) const + { + result = code; + last_checked = system_time(); + checked = true; + } + +/* +* Check if this certificate can be trusted +*/ +bool X509_Store::Cert_Info::is_trusted() const + { + return trusted; + } + +/* +* Check if this certificate has been verified +*/ +bool X509_Store::Cert_Info::is_verified(u32bit timeout) const + { + if(!checked) + return false; + if(result != VERIFIED && result != CERT_NOT_YET_VALID) + return true; + + const u64bit current_time = system_time(); + + if(current_time > last_checked + timeout) + checked = false; + + return checked; + } + +} +/* +* Adler32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +void adler32_update(const byte input[], size_t length, + u16bit& S1, u16bit& S2) + { + u32bit S1x = S1; + u32bit S2x = S2; + + while(length >= 16) + { + S1x += input[ 0]; S2x += S1x; + S1x += input[ 1]; S2x += S1x; + S1x += input[ 2]; S2x += S1x; + S1x += input[ 3]; S2x += S1x; + S1x += input[ 4]; S2x += S1x; + S1x += input[ 5]; S2x += S1x; + S1x += input[ 6]; S2x += S1x; + S1x += input[ 7]; S2x += S1x; + S1x += input[ 8]; S2x += S1x; + S1x += input[ 9]; S2x += S1x; + S1x += input[10]; S2x += S1x; + S1x += input[11]; S2x += S1x; + S1x += input[12]; S2x += S1x; + S1x += input[13]; S2x += S1x; + S1x += input[14]; S2x += S1x; + S1x += input[15]; S2x += S1x; + input += 16; + length -= 16; + } + + for(size_t j = 0; j != length; ++j) + { + S1x += input[j]; + S2x += S1x; + } + + S1 = S1x % 65521; + S2 = S2x % 65521; + } + +} + +/* +* Update an Adler32 Checksum +*/ +void Adler32::add_data(const byte input[], size_t length) + { + const size_t PROCESS_AMOUNT = 5552; + + while(length >= PROCESS_AMOUNT) + { + adler32_update(input, PROCESS_AMOUNT, S1, S2); + input += PROCESS_AMOUNT; + length -= PROCESS_AMOUNT; + } + + adler32_update(input, length, S1, S2); + } + +/* +* Finalize an Adler32 Checksum +*/ +void Adler32::final_result(byte output[]) + { + store_be(output, S2, S1); + clear(); + } + +} +/* +* CRC24 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Update a CRC24 Checksum +*/ +void CRC24::add_data(const byte input[], size_t length) + { + const u32bit TABLE[256] = { + 0x00000000, 0x00864CFB, 0x008AD50D, 0x000C99F6, 0x0093E6E1, 0x0015AA1A, + 0x001933EC, 0x009F7F17, 0x00A18139, 0x0027CDC2, 0x002B5434, 0x00AD18CF, + 0x003267D8, 0x00B42B23, 0x00B8B2D5, 0x003EFE2E, 0x00C54E89, 0x00430272, + 0x004F9B84, 0x00C9D77F, 0x0056A868, 0x00D0E493, 0x00DC7D65, 0x005A319E, + 0x0064CFB0, 0x00E2834B, 0x00EE1ABD, 0x00685646, 0x00F72951, 0x007165AA, + 0x007DFC5C, 0x00FBB0A7, 0x000CD1E9, 0x008A9D12, 0x008604E4, 0x0000481F, + 0x009F3708, 0x00197BF3, 0x0015E205, 0x0093AEFE, 0x00AD50D0, 0x002B1C2B, + 0x002785DD, 0x00A1C926, 0x003EB631, 0x00B8FACA, 0x00B4633C, 0x00322FC7, + 0x00C99F60, 0x004FD39B, 0x00434A6D, 0x00C50696, 0x005A7981, 0x00DC357A, + 0x00D0AC8C, 0x0056E077, 0x00681E59, 0x00EE52A2, 0x00E2CB54, 0x006487AF, + 0x00FBF8B8, 0x007DB443, 0x00712DB5, 0x00F7614E, 0x0019A3D2, 0x009FEF29, + 0x009376DF, 0x00153A24, 0x008A4533, 0x000C09C8, 0x0000903E, 0x0086DCC5, + 0x00B822EB, 0x003E6E10, 0x0032F7E6, 0x00B4BB1D, 0x002BC40A, 0x00AD88F1, + 0x00A11107, 0x00275DFC, 0x00DCED5B, 0x005AA1A0, 0x00563856, 0x00D074AD, + 0x004F0BBA, 0x00C94741, 0x00C5DEB7, 0x0043924C, 0x007D6C62, 0x00FB2099, + 0x00F7B96F, 0x0071F594, 0x00EE8A83, 0x0068C678, 0x00645F8E, 0x00E21375, + 0x0015723B, 0x00933EC0, 0x009FA736, 0x0019EBCD, 0x008694DA, 0x0000D821, + 0x000C41D7, 0x008A0D2C, 0x00B4F302, 0x0032BFF9, 0x003E260F, 0x00B86AF4, + 0x002715E3, 0x00A15918, 0x00ADC0EE, 0x002B8C15, 0x00D03CB2, 0x00567049, + 0x005AE9BF, 0x00DCA544, 0x0043DA53, 0x00C596A8, 0x00C90F5E, 0x004F43A5, + 0x0071BD8B, 0x00F7F170, 0x00FB6886, 0x007D247D, 0x00E25B6A, 0x00641791, + 0x00688E67, 0x00EEC29C, 0x003347A4, 0x00B50B5F, 0x00B992A9, 0x003FDE52, + 0x00A0A145, 0x0026EDBE, 0x002A7448, 0x00AC38B3, 0x0092C69D, 0x00148A66, + 0x00181390, 0x009E5F6B, 0x0001207C, 0x00876C87, 0x008BF571, 0x000DB98A, + 0x00F6092D, 0x007045D6, 0x007CDC20, 0x00FA90DB, 0x0065EFCC, 0x00E3A337, + 0x00EF3AC1, 0x0069763A, 0x00578814, 0x00D1C4EF, 0x00DD5D19, 0x005B11E2, + 0x00C46EF5, 0x0042220E, 0x004EBBF8, 0x00C8F703, 0x003F964D, 0x00B9DAB6, + 0x00B54340, 0x00330FBB, 0x00AC70AC, 0x002A3C57, 0x0026A5A1, 0x00A0E95A, + 0x009E1774, 0x00185B8F, 0x0014C279, 0x00928E82, 0x000DF195, 0x008BBD6E, + 0x00872498, 0x00016863, 0x00FAD8C4, 0x007C943F, 0x00700DC9, 0x00F64132, + 0x00693E25, 0x00EF72DE, 0x00E3EB28, 0x0065A7D3, 0x005B59FD, 0x00DD1506, + 0x00D18CF0, 0x0057C00B, 0x00C8BF1C, 0x004EF3E7, 0x00426A11, 0x00C426EA, + 0x002AE476, 0x00ACA88D, 0x00A0317B, 0x00267D80, 0x00B90297, 0x003F4E6C, + 0x0033D79A, 0x00B59B61, 0x008B654F, 0x000D29B4, 0x0001B042, 0x0087FCB9, + 0x001883AE, 0x009ECF55, 0x009256A3, 0x00141A58, 0x00EFAAFF, 0x0069E604, + 0x00657FF2, 0x00E33309, 0x007C4C1E, 0x00FA00E5, 0x00F69913, 0x0070D5E8, + 0x004E2BC6, 0x00C8673D, 0x00C4FECB, 0x0042B230, 0x00DDCD27, 0x005B81DC, + 0x0057182A, 0x00D154D1, 0x0026359F, 0x00A07964, 0x00ACE092, 0x002AAC69, + 0x00B5D37E, 0x00339F85, 0x003F0673, 0x00B94A88, 0x0087B4A6, 0x0001F85D, + 0x000D61AB, 0x008B2D50, 0x00145247, 0x00921EBC, 0x009E874A, 0x0018CBB1, + 0x00E37B16, 0x006537ED, 0x0069AE1B, 0x00EFE2E0, 0x00709DF7, 0x00F6D10C, + 0x00FA48FA, 0x007C0401, 0x0042FA2F, 0x00C4B6D4, 0x00C82F22, 0x004E63D9, + 0x00D11CCE, 0x00575035, 0x005BC9C3, 0x00DD8538 }; + + u32bit tmp = crc; + while(length >= 16) + { + tmp = TABLE[((tmp >> 16) ^ input[ 0]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 1]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 2]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 3]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 4]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 5]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 6]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 7]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 8]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[ 9]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[10]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[11]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[12]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[13]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[14]) & 0xFF] ^ (tmp << 8); + tmp = TABLE[((tmp >> 16) ^ input[15]) & 0xFF] ^ (tmp << 8); + input += 16; + length -= 16; + } + + for(size_t i = 0; i != length; ++i) + tmp = TABLE[((tmp >> 16) ^ input[i]) & 0xFF] ^ (tmp << 8); + + crc = tmp; + } + +/* +* Finalize a CRC24 Checksum +*/ +void CRC24::final_result(byte output[]) + { + for(size_t i = 0; i != 3; ++i) + output[i] = get_byte(i+1, crc); + clear(); + } + +} +/* +* CRC32 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Update a CRC32 Checksum +*/ +void CRC32::add_data(const byte input[], size_t length) + { + const u32bit TABLE[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + + u32bit tmp = crc; + while(length >= 16) + { + tmp = TABLE[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8); + tmp = TABLE[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8); + input += 16; + length -= 16; + } + + for(size_t i = 0; i != length; ++i) + tmp = TABLE[(tmp ^ input[i]) & 0xFF] ^ (tmp >> 8); + + crc = tmp; + } + +/* +* Finalize a CRC32 Checksum +*/ +void CRC32::final_result(byte output[]) + { + crc ^= 0xFFFFFFFF; + store_be(crc, output); + clear(); + } + +} +/* +* Base64 Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +static const byte BIN_TO_BASE64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +void do_base64_encode(char out[4], const byte in[3]) + { + out[0] = BIN_TO_BASE64[((in[0] & 0xFC) >> 2)]; + out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)]; + out[3] = BIN_TO_BASE64[((in[2] & 0x3F) )]; + } + +} + +size_t base64_encode(char out[], + const byte in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + input_consumed = 0; + + size_t input_remaining = input_length; + size_t output_produced = 0; + + while(input_remaining >= 3) + { + do_base64_encode(out + output_produced, in + input_consumed); + + input_consumed += 3; + output_produced += 4; + input_remaining -= 3; + } + + if(final_inputs && input_remaining) + { + byte remainder[3] = { 0 }; + for(size_t i = 0; i != input_remaining; ++i) + remainder[i] = in[input_consumed + i]; + + do_base64_encode(out + output_produced, remainder); + + size_t empty_bits = 8 * (3 - input_remaining); + size_t index = output_produced + 4 - 1; + while(empty_bits >= 8) + { + out[index--] = '='; + empty_bits -= 6; + } + + input_consumed += input_remaining; + output_produced += 4; + } + + return output_produced; + } + +std::string base64_encode(const byte input[], + size_t input_length) + { + std::string output((round_up(input_length, 3) / 3) * 4, 0); + + size_t consumed = 0; + size_t produced = base64_encode(&output[0], + input, input_length, + consumed, true); + + BOTAN_ASSERT_EQUAL(consumed, input_length, "Did not consume all input"); + BOTAN_ASSERT_EQUAL(produced, output.size(), "Did not produce right amount"); + + return output; + } + +std::string base64_encode(const MemoryRegion& input) + { + return base64_encode(&input[0], input.size()); + } + +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + /* + * Base64 Decoder Lookup Table + * Warning: assumes ASCII encodings + */ + static const byte BASE64_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, + 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + byte decode_buf[4]; + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, input_length * 3 / 4); + + for(size_t i = 0; i != input_length; ++i) + { + const byte bin = BASE64_TO_BIN[static_cast(input[i])]; + + if(bin <= 0x3F) + { + decode_buf[decode_buf_pos] = bin; + decode_buf_pos += 1; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + else if(bad_char == "\r") + bad_char = "\\r"; + + throw std::invalid_argument( + std::string("base64_decode: invalid base64 character '") + + bad_char + "'"); + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t i = decode_buf_pos; i != 4; ++i) + decode_buf[i] = 0; + final_truncate = (4 - decode_buf_pos); + decode_buf_pos = 4; + } + } + + if(decode_buf_pos == 4) + { + out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); + out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); + out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; + + out_ptr += 3; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + BASE64_TO_BIN[static_cast(input[input_consumed])] == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - final_truncate; + + return written; + } + +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = base64_decode(output, input, input_length, + consumed, true, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("base64_decode: input did not have full bytes"); + + return written; + } + +size_t base64_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return base64_decode(output, &input[0], input.length(), ignore_ws); + } + +SecureVector base64_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + SecureVector bin((round_up(input_length, 4) * 3) / 4); + + size_t written = base64_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +SecureVector base64_decode(const std::string& input, + bool ignore_ws) + { + return base64_decode(&input[0], input.size(), ignore_ws); + } + + +} +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void hex_encode(char output[], + const byte input[], + size_t input_length, + bool uppercase) + { + static const byte BIN_TO_HEX_UPPER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + + static const byte BIN_TO_HEX_LOWER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER; + + for(size_t i = 0; i != input_length; ++i) + { + byte x = input[i]; + output[2*i ] = tbl[(x >> 4) & 0x0F]; + output[2*i+1] = tbl[(x ) & 0x0F]; + } + } + +std::string hex_encode(const MemoryRegion& input, + bool uppercase) + { + return hex_encode(&input[0], input.size(), uppercase); + } + +std::string hex_encode(const byte input[], + size_t input_length, + bool uppercase) + { + std::string output(2 * input_length, 0); + + if(input_length) + hex_encode(&output[0], input, input_length, uppercase); + + return output; + } + +size_t hex_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws) + { + /* + * Mapping of hex characters to either their binary equivalent + * or to an error code. + * If valid hex (0-9 A-F a-f), the value. + * If whitespace, then 0x80 + * Otherwise 0xFF + * Warning: this table assumes ASCII character encodings + */ + + static const byte HEX_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + bool top_nibble = true; + + clear_mem(output, input_length / 2); + + for(size_t i = 0; i != input_length; ++i) + { + const byte bin = HEX_TO_BIN[static_cast(input[i])]; + + if(bin >= 0x10) + { + if(bin == 0x80 && ignore_ws) + continue; + + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + + throw std::invalid_argument( + std::string("hex_decode: invalid hex character '") + + bad_char + "'"); + } + + *out_ptr |= bin << (top_nibble*4); + + top_nibble = !top_nibble; + if(top_nibble) + ++out_ptr; + } + + input_consumed = input_length; + size_t written = (out_ptr - output); + + /* + * We only got half of a byte at the end; zap the half-written + * output and mark it as unread + */ + if(!top_nibble) + { + *out_ptr = 0; + input_consumed -= 1; + } + + return written; + } + +size_t hex_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = hex_decode(output, input, input_length, + consumed, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("hex_decode: input did not have full bytes"); + + return written; + } + +size_t hex_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return hex_decode(output, &input[0], input.length(), ignore_ws); + } + +SecureVector hex_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + SecureVector bin(1 + input_length / 2); + + size_t written = hex_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +SecureVector hex_decode(const std::string& input, + bool ignore_ws) + { + return hex_decode(&input[0], input.size(), ignore_ws); + } + +} +/* +* OpenPGP Codec +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* OpenPGP Base64 encoding +*/ +std::string PGP_encode( + const byte input[], size_t length, + const std::string& label, + const std::map& headers) + { + const std::string PGP_HEADER = "-----BEGIN PGP " + label + "-----\n"; + const std::string PGP_TRAILER = "-----END PGP " + label + "-----\n"; + const size_t PGP_WIDTH = 64; + + std::string pgp_encoded = PGP_HEADER; + + if(headers.find("Version") != headers.end()) + pgp_encoded += "Version: " + headers.find("Version")->second + '\n'; + + std::map::const_iterator i = headers.begin(); + while(i != headers.end()) + { + if(i->first != "Version") + pgp_encoded += i->first + ": " + i->second + '\n'; + ++i; + } + pgp_encoded += '\n'; + + Pipe pipe(new Fork( + new Base64_Encoder(true, PGP_WIDTH), + new Chain(new Hash_Filter(new CRC24), new Base64_Encoder) + ) + ); + + pipe.process_msg(input, length); + + pgp_encoded += pipe.read_all_as_string(0); + pgp_encoded += '=' + pipe.read_all_as_string(1) + '\n'; + pgp_encoded += PGP_TRAILER; + + return pgp_encoded; + } + +/* +* OpenPGP Base64 encoding +*/ +std::string PGP_encode(const byte input[], size_t length, + const std::string& type) + { + std::map empty; + return PGP_encode(input, length, type, empty); + } + +/* +* OpenPGP Base64 decoding +*/ +SecureVector PGP_decode(DataSource& source, + std::string& label, + std::map& headers) + { + const size_t RANDOM_CHAR_LIMIT = 5; + + const std::string PGP_HEADER1 = "-----BEGIN PGP "; + const std::string PGP_HEADER2 = "-----"; + size_t position = 0; + + while(position != PGP_HEADER1.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PGP: Malformed PGP header"); + else + position = 0; + } + position = 0; + while(position != PGP_HEADER2.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP header"); + + if(position == 0) + label += static_cast(b); + } + + headers.clear(); + bool end_of_headers = false; + while(!end_of_headers) + { + std::string this_header; + byte b = 0; + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad armor header"); + if(b != '\n') + this_header += static_cast(b); + } + + end_of_headers = true; + for(size_t j = 0; j != this_header.length(); ++j) + if(!Charset::is_space(this_header[j])) + end_of_headers = false; + + if(!end_of_headers) + { + std::string::size_type pos = this_header.find(": "); + if(pos == std::string::npos) + throw Decoding_Error("OpenPGP: Bad headers"); + + std::string key = this_header.substr(0, pos); + std::string value = this_header.substr(pos + 2, std::string::npos); + headers[key] = value; + } + } + + Pipe base64(new Base64_Decoder, + new Fork(0, + new Chain(new Hash_Filter(new CRC24), + new Base64_Encoder) + ) + ); + base64.start_msg(); + + const std::string PGP_TRAILER = "-----END PGP " + label + "-----"; + position = 0; + bool newline_seen = 0; + std::string crc; + while(position != PGP_TRAILER.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP trailer found"); + if(b == PGP_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP trailer"); + + if(b == '=' && newline_seen) + { + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad CRC tail"); + if(b != '\n') + crc += static_cast(b); + } + } + else if(b == '\n') + newline_seen = true; + else if(position == 0) + { + base64.write(b); + newline_seen = false; + } + } + base64.end_msg(); + + if(crc != "" && crc != base64.read_all_as_string(1)) + throw Decoding_Error("PGP: Corrupt CRC"); + + return base64.read_all(); + } + +/* +* OpenPGP Base64 decoding +*/ +SecureVector PGP_decode(DataSource& source, std::string& label) + { + std::map ignored; + return PGP_decode(source, label, ignored); + } + +} + +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace PEM_Code { + +/* +* PEM encode BER/DER-encoded objects +*/ +std::string encode(const byte der[], size_t length, const std::string& label, + size_t width) + { + const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; + const std::string PEM_TRAILER = "-----END " + label + "-----\n"; + + Pipe pipe(new Base64_Encoder(true, width)); + pipe.process_msg(der, length); + return (PEM_HEADER + pipe.read_all_as_string() + PEM_TRAILER); + } + +/* +* PEM encode BER/DER-encoded objects +*/ +std::string encode(const MemoryRegion& data, const std::string& label, + size_t width) + { + return encode(&data[0], data.size(), label, width); + } + +/* +* Decode PEM down to raw BER/DER +*/ +SecureVector decode_check_label(DataSource& source, + const std::string& label_want) + { + std::string label_got; + SecureVector ber = decode(source, label_got); + if(label_got != label_want) + throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + + ", got " + label_got); + return ber; + } + +/* +* Decode PEM down to raw BER/DER +*/ +SecureVector decode(DataSource& source, std::string& label) + { + const size_t RANDOM_CHAR_LIMIT = 8; + + const std::string PEM_HEADER1 = "-----BEGIN "; + const std::string PEM_HEADER2 = "-----"; + size_t position = 0; + + while(position != PEM_HEADER1.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PEM: Malformed PEM header"); + else + position = 0; + } + position = 0; + while(position != PEM_HEADER2.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM header"); + + if(position == 0) + label += static_cast(b); + } + + Pipe base64(new Base64_Decoder); + base64.start_msg(); + + const std::string PEM_TRAILER = "-----END " + label + "-----"; + position = 0; + while(position != PEM_TRAILER.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM trailer found"); + if(b == PEM_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM trailer"); + + if(position == 0) + base64.write(b); + } + base64.end_msg(); + return base64.read_all(); + } + +/* +* Search for a PEM signature +*/ +bool matches(DataSource& source, const std::string& extra, + size_t search_range) + { + const std::string PEM_HEADER = "-----BEGIN " + extra; + + SecureVector search_buf(search_range); + size_t got = source.peek(&search_buf[0], search_buf.size(), 0); + + if(got < PEM_HEADER.length()) + return false; + + size_t index = 0; + + for(size_t j = 0; j != got; ++j) + { + if(search_buf[j] == PEM_HEADER[index]) + ++index; + else + index = 0; + if(index == PEM_HEADER.size()) + return true; + } + return false; + } + +} + +} +/* +* Rivest's Package Tranform +* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +void aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]) + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::package: Invalid cipher"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + SymmetricKey package_key(rng, BLOCK_SIZE); + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len); + pipe.read(output, pipe.remaining()); + + // Set K0 (the all zero key) + cipher->set_key(SymmetricKey(all_zeros)); + + SecureVector buf(BLOCK_SIZE); + + const size_t blocks = + (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE; + + byte* final_block = output + input_len; + clear_mem(final_block, BLOCK_SIZE); + + // XOR the hash blocks into the final block + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * i); + + zeroise(buf); + copy_mem(&buf[0], output + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(buf); + + xor_buf(final_block, buf, BLOCK_SIZE); + } + + // XOR the random package key into the final block + xor_buf(final_block, package_key.begin(), BLOCK_SIZE); + } + +void aont_unpackage(BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]) + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::unpackage: Invalid cipher"); + + if(input_len < BLOCK_SIZE) + throw Invalid_Argument("AONT::unpackage: Input too short"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + cipher->set_key(SymmetricKey(all_zeros)); + + SecureVector package_key(BLOCK_SIZE); + SecureVector buf(BLOCK_SIZE); + + // Copy the package key (masked with the block hashes) + copy_mem(&package_key[0], + input + (input_len - BLOCK_SIZE), + BLOCK_SIZE); + + const size_t blocks = ((input_len - 1) / BLOCK_SIZE); + + // XOR the blocks into the package key bits + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * (i+1)); + + zeroise(buf); + copy_mem(&buf[0], input + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(buf); + + xor_buf(&package_key[0], buf, BLOCK_SIZE); + } + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len - BLOCK_SIZE); + + pipe.read(output, pipe.remaining()); + } + +} +/* +* Cryptobox Message Routines +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace CryptoBox { + +namespace { + +/* +First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits +for later use as flags, etc if needed +*/ +const u32bit CRYPTOBOX_VERSION_CODE = 0xEFC22400; + +const size_t VERSION_CODE_LEN = 4; +const size_t CIPHER_KEY_LEN = 32; +const size_t CIPHER_IV_LEN = 16; +const size_t MAC_KEY_LEN = 32; +const size_t MAC_OUTPUT_LEN = 20; +const size_t PBKDF_SALT_LEN = 10; +const size_t PBKDF_ITERATIONS = 8 * 1024; + +const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + CIPHER_IV_LEN + MAC_KEY_LEN; + +} + +std::string encrypt(const byte input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng) + { + SecureVector pbkdf_salt(PBKDF_SALT_LEN); + rng.randomize(&pbkdf_salt[0], pbkdf_salt.size()); + + PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); + + OctetString master_key = pbkdf.derive_key( + PBKDF_OUTPUT_LEN, + passphrase, + &pbkdf_salt[0], + pbkdf_salt.size(), + PBKDF_ITERATIONS); + + const byte* mk = master_key.begin(); + + SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN); + SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN); + InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN); + + Pipe pipe(get_cipher("Serpent/CTR-BE", cipher_key, iv, ENCRYPTION), + new Fork( + 0, + new MAC_Filter(new HMAC(new SHA_512), + mac_key, MAC_OUTPUT_LEN))); + + pipe.process_msg(input, input_len); + + /* + Output format is: + version # (4 bytes) + salt (10 bytes) + mac (20 bytes) + ciphertext + */ + const size_t ciphertext_len = pipe.remaining(0); + + SecureVector out_buf(VERSION_CODE_LEN + + PBKDF_SALT_LEN + + MAC_OUTPUT_LEN + + ciphertext_len); + + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE); + + copy_mem(&out_buf[VERSION_CODE_LEN], &pbkdf_salt[0], PBKDF_SALT_LEN); + + pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], MAC_OUTPUT_LEN, 1); + pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN], + ciphertext_len, 0); + + return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE"); + } + +std::string decrypt(const byte input[], size_t input_len, + const std::string& passphrase) + { + DataSource_Memory input_src(input, input_len); + SecureVector ciphertext = + PEM_Code::decode_check_label(input_src, + "BOTAN CRYPTOBOX MESSAGE"); + + if(ciphertext.size() < (VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN)) + throw Decoding_Error("Invalid CryptoBox input"); + + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE)) + throw Decoding_Error("Bad CryptoBox version"); + + const byte* pbkdf_salt = &ciphertext[VERSION_CODE_LEN]; + + PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); + + OctetString master_key = pbkdf.derive_key( + PBKDF_OUTPUT_LEN, + passphrase, + pbkdf_salt, + PBKDF_SALT_LEN, + PBKDF_ITERATIONS); + + const byte* mk = master_key.begin(); + + SymmetricKey cipher_key(&mk[0], CIPHER_KEY_LEN); + SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN); + InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN); + + Pipe pipe(new Fork( + get_cipher("Serpent/CTR-BE", cipher_key, iv, DECRYPTION), + new MAC_Filter(new HMAC(new SHA_512), + mac_key, MAC_OUTPUT_LEN))); + + const size_t ciphertext_offset = + VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN; + + pipe.process_msg(&ciphertext[ciphertext_offset], + ciphertext.size() - ciphertext_offset); + + byte computed_mac[MAC_OUTPUT_LEN]; + pipe.read(computed_mac, MAC_OUTPUT_LEN, 1); + + if(!same_mem(computed_mac, + &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN], + MAC_OUTPUT_LEN)) + throw Decoding_Error("CryptoBox integrity failure"); + + return pipe.read_all_as_string(0); + } + +std::string decrypt(const std::string& input, + const std::string& passphrase) + { + return decrypt(reinterpret_cast(&input[0]), + input.size(), + passphrase); + } + +} + +} +/* +* Format Preserving Encryption using the scheme FE1 from the paper +* "Format-Preserving Encryption" by Bellare, Rogaway, et al +* (http://eprint.iacr.org/2009/251) +* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace FPE { + +namespace { + +// Normally FPE is for SSNs, CC#s, etc, nothing too big +const size_t MAX_N_BYTES = 128/8; + +/* +* Factor n into a and b which are as close together as possible. +* Assumes n is composed mostly of small factors which is the case for +* typical uses of FPE (typically, n is a power of 10) +* +* Want a >= b since the safe number of rounds is 2+log_a(b); if a >= b +* then this is always 3 +*/ +void factor(BigInt n, BigInt& a, BigInt& b) + { + a = 1; + b = 1; + + size_t n_low_zero = low_zero_bits(n); + + a <<= (n_low_zero / 2); + b <<= n_low_zero - (n_low_zero / 2); + n >>= n_low_zero; + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + while(n % PRIMES[i] == 0) + { + a *= PRIMES[i]; + if(a > b) + std::swap(a, b); + n /= PRIMES[i]; + } + } + + if(a > b) + std::swap(a, b); + a *= n; + if(a < b) + std::swap(a, b); + + if(a <= 1 || b <= 1) + throw std::runtime_error("Could not factor n for use in FPE"); + } + +/* +* According to a paper by Rogaway, Bellare, etc, the min safe number +* of rounds to use for FPE is 2+log_a(b). If a >= b then log_a(b) <= 1 +* so 3 rounds is safe. The FPE factorization routine should always +* return a >= b, so just confirm that and return 3. +*/ +size_t rounds(const BigInt& a, const BigInt& b) + { + if(a < b) + throw std::logic_error("FPE rounds: a < b"); + return 3; + } + +/* +* A simple round function based on HMAC(SHA-256) +*/ +class FPE_Encryptor + { + public: + FPE_Encryptor(const SymmetricKey& key, + const BigInt& n, + const MemoryRegion& tweak); + + ~FPE_Encryptor() { delete mac; } + + BigInt operator()(size_t i, const BigInt& R); + + private: + MessageAuthenticationCode* mac; + SecureVector mac_n_t; + }; + +FPE_Encryptor::FPE_Encryptor(const SymmetricKey& key, + const BigInt& n, + const MemoryRegion& tweak) + { + mac = new HMAC(new SHA_256); + mac->set_key(key); + + SecureVector n_bin = BigInt::encode(n); + + if(n_bin.size() > MAX_N_BYTES) + throw std::runtime_error("N is too large for FPE encryption"); + + mac->update_be(static_cast(n_bin.size())); + mac->update(&n_bin[0], n_bin.size()); + + mac->update_be(static_cast(tweak.size())); + mac->update(&tweak[0], tweak.size()); + + mac_n_t = mac->final(); + } + +BigInt FPE_Encryptor::operator()(size_t round_no, const BigInt& R) + { + SecureVector r_bin = BigInt::encode(R); + + mac->update(mac_n_t); + mac->update_be(static_cast(round_no)); + + mac->update_be(static_cast(r_bin.size())); + mac->update(&r_bin[0], r_bin.size()); + + SecureVector X = mac->final(); + return BigInt(&X[0], X.size()); + } + +} + +/* +* Generic Z_n FPE encryption, FE1 scheme +*/ +BigInt fe1_encrypt(const BigInt& n, const BigInt& X0, + const SymmetricKey& key, + const MemoryRegion& tweak) + { + FPE_Encryptor F(key, n, tweak); + + BigInt a, b; + factor(n, a, b); + + const size_t r = rounds(a, b); + + BigInt X = X0; + + for(size_t i = 0; i != r; ++i) + { + BigInt L = X / b; + BigInt R = X % b; + + BigInt W = (L + F(i, R)) % a; + X = a * R + W; + } + + return X; + } + +/* +* Generic Z_n FPE decryption, FD1 scheme +*/ +BigInt fe1_decrypt(const BigInt& n, const BigInt& X0, + const SymmetricKey& key, + const MemoryRegion& tweak) + { + FPE_Encryptor F(key, n, tweak); + + BigInt a, b; + factor(n, a, b); + + const size_t r = rounds(a, b); + + BigInt X = X0; + + for(size_t i = 0; i != r; ++i) + { + BigInt W = X % a; + BigInt R = X / a; + + BigInt L = (W - F(r-i-1, R)) % a; + X = b * L + R; + } + + return X; + } + +} + +} +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +BlockCipher* make_aes(size_t keylength, + Algorithm_Factory& af) + { + if(keylength == 16) + return af.make_block_cipher("AES-128"); + else if(keylength == 24) + return af.make_block_cipher("AES-192"); + else if(keylength == 32) + return af.make_block_cipher("AES-256"); + else + throw std::invalid_argument("Bad KEK length for NIST keywrap"); + } + +} + +SecureVector rfc3394_keywrap(const MemoryRegion& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key wrap"); + + std::unique_ptr aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = key.size() / 8; + + SecureVector R((n + 1) * 8); + SecureVector A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = 0xA6; + + copy_mem(&R[8], key.begin(), key.size()); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = 1; i <= n; ++i) + { + const u32bit t = (n * j) + i; + + copy_mem(&A[8], &R[8*i], 8); + + aes->encrypt(&A[0]); + copy_mem(&R[8*i], &A[8], 8); + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + xor_buf(&A[4], &t_buf[0], 4); + } + } + + copy_mem(&R[0], &A[0], 8); + + return R; + } + +SecureVector rfc3394_keyunwrap(const MemoryRegion& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() < 16 || key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key unwrap"); + + std::unique_ptr aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = (key.size() - 8) / 8; + + SecureVector R(n * 8); + SecureVector A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = key[i]; + + copy_mem(&R[0], key.begin() + 8, key.size() - 8); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = n; i != 0; --i) + { + const u32bit t = (5 - j) * n + i; + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + + xor_buf(&A[4], &t_buf[0], 4); + + copy_mem(&A[8], &R[8*(i-1)], 8); + + aes->decrypt(&A[0]); + + copy_mem(&R[8*(i-1)], &A[8], 8); + } + } + + if(load_be(&A[0], 0) != 0xA6A6A6A6A6A6A6A6ULL) + throw Integrity_Failure("NIST key unwrap failed"); + + return R; + } + +} +/* +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +BigInt hash_seq(const std::string& hash_id, + size_t pad_to, + const BigInt& in1, + const BigInt& in2) + { + std::unique_ptr hash_fn( + global_state().algorithm_factory().make_hash_function(hash_id)); + + hash_fn->update(BigInt::encode_1363(in1, pad_to)); + hash_fn->update(BigInt::encode_1363(in2, pad_to)); + + return BigInt::decode(hash_fn->final()); + } + +BigInt compute_x(const std::string& hash_id, + const std::string& identifier, + const std::string& password, + const MemoryRegion& salt) + { + std::unique_ptr hash_fn( + global_state().algorithm_factory().make_hash_function(hash_id)); + + hash_fn->update(identifier); + hash_fn->update(":"); + hash_fn->update(password); + + SecureVector inner_h = hash_fn->final(); + + hash_fn->update(salt); + hash_fn->update(inner_h); + + SecureVector outer_h = hash_fn->final(); + + return BigInt::decode(outer_h); + } + +} + +std::string srp6_group_identifier(const BigInt& N, const BigInt& g) + { + /* + This function assumes that only one 'standard' SRP parameter set has + been defined for a particular bitsize. As of this writing that is the case. + */ + try + { + const std::string group_name = "modp/srp/" + to_string(N.bits()); + + DL_Group group(group_name); + + if(group.get_p() == N && group.get_g() == g) + return group_name; + + throw std::runtime_error("Unknown SRP params"); + } + catch(...) + { + throw Invalid_Argument("Bad SRP group parameters"); + } + } + +std::pair +srp6_client_agree(const std::string& identifier, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const MemoryRegion& salt, + const BigInt& B, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + const size_t p_bytes = group.get_p().bytes(); + + if(B % p == 0) + throw std::runtime_error("Invalid SRP parameter from server"); + + BigInt k = hash_seq(hash_id, p_bytes, p, g); + + BigInt a(rng, 256); + + BigInt A = power_mod(g, a, p); + + BigInt u = hash_seq(hash_id, p_bytes, A, B); + + const BigInt x = compute_x(hash_id, identifier, password, salt); + + BigInt S = power_mod((B - (k * power_mod(g, x, p))) % p, (a + (u * x)), p); + + SymmetricKey Sk(BigInt::encode_1363(S, p_bytes)); + + return std::make_pair(A, Sk); + } + +BigInt generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const MemoryRegion& salt, + const std::string& group_id, + const std::string& hash_id) + { + const BigInt x = compute_x(hash_id, identifier, password, salt); + + DL_Group group(group_id); + return power_mod(group.get_g(), x, group.get_p()); + } + +BigInt SRP6_Server_Session::step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + p_bytes = p.bytes(); + + BigInt k = hash_seq(hash_id, p_bytes, p, g); + + BigInt b(rng, 256); + + B = (v*k + power_mod(g, b, p)) % p; + + this->v = v; + this->b = b; + this->p = p; + this->hash_id = hash_id; + + return B; + } + +SymmetricKey SRP6_Server_Session::step2(const BigInt& A) + { + if(A % p == 0) + throw std::runtime_error("Invalid SRP parameter from client"); + + BigInt u = hash_seq(hash_id, p_bytes, A, B); + + BigInt S = power_mod(A * power_mod(v, u, p), b, p); + + return BigInt::encode_1363(S, p_bytes); + } + +} +/* +* RTSS (threshold secret sharing) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/** +Table for GF(2^8) arithmetic (exponentials) +*/ +const byte RTSS_EXP[256] = { +0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, +0x96, 0xA1, 0xF8, 0x13, 0x35, 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, +0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA, 0xE5, +0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, +0x90, 0xAB, 0xE6, 0x31, 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, +0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD, 0x4C, 0xD4, +0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, +0x28, 0x78, 0x88, 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, +0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A, 0xB5, 0xC4, 0x57, +0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, +0x61, 0xA3, 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, +0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0, 0xFB, 0x16, 0x3A, 0x4E, +0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, +0x41, 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, +0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75, 0x9F, 0xBA, 0xD5, 0x64, 0xAC, +0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80, +0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, +0xB1, 0xC8, 0x43, 0xC5, 0x54, 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, +0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA, 0x45, +0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, +0xC6, 0x51, 0xF3, 0x0E, 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, +0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17, 0x39, 0x4B, +0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, +0x52, 0xF6, 0x01 }; + +/** +Table for GF(2^8) arithmetic (logarithms) +*/ +const byte RTSS_LOG[] = { +0x90, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, +0x68, 0x33, 0xEE, 0xDF, 0x03, 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, +0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1, 0x7D, +0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, +0x9A, 0xC9, 0x09, 0x78, 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, +0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E, 0x96, 0x8F, +0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, +0x46, 0x83, 0x38, 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, +0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10, 0x7E, 0x6E, 0x48, +0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, +0x3D, 0xBA, 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, +0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57, 0xAF, 0x58, 0xA8, 0x50, +0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, +0xE8, 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, +0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0, 0x7F, 0x0C, 0xF6, 0x6F, 0x17, +0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7, +0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, +0x6C, 0xAA, 0x55, 0x29, 0x9D, 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, +0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1, 0x53, +0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, +0x56, 0xF2, 0xD3, 0xAB, 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, +0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5, 0x67, 0x4A, +0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, +0xF7, 0x70, 0x07 }; + +byte gfp_mul(byte x, byte y) + { + if(x == 0 || y == 0) + return 0; + return RTSS_EXP[(RTSS_LOG[x] + RTSS_LOG[y]) % 255]; + } + +byte rtss_hash_id(const std::string& hash_name) + { + if(hash_name == "SHA-160") + return 1; + else if(hash_name == "SHA-256") + return 2; + else + throw Invalid_Argument("RTSS only supports SHA-1 and SHA-256"); + } + +HashFunction* get_rtss_hash_by_id(byte id) + { + if(id == 1) + return new SHA_160; + else if(id == 2) + return new SHA_256; + else + throw Decoding_Error("Bad RTSS hash identifier"); + } + +} + +RTSS_Share::RTSS_Share(const std::string& hex_input) + { + contents = hex_decode(hex_input); + } + +byte RTSS_Share::share_id() const + { + if(!initialized()) + throw Invalid_State("RTSS_Share::share_id not initialized"); + + return contents[20]; + } + +std::string RTSS_Share::to_string() const + { + return hex_encode(&contents[0], contents.size()); + } + +std::vector +RTSS_Share::split(byte M, byte N, + const byte S[], u16bit S_len, + const byte identifier[16], + RandomNumberGenerator& rng) + { + if(M == 0 || N == 0 || M > N) + throw Encoding_Error("RTSS_Share::split: M == 0 or N == 0 or M > N"); + + SHA_256 hash; // always use SHA-256 when generating shares + + std::vector shares(N); + + // Create RTSS header in each share + for(byte i = 0; i != N; ++i) + { + shares[i].contents += std::make_pair(identifier, 16); + shares[i].contents += rtss_hash_id(hash.name()); + shares[i].contents += M; + shares[i].contents += get_byte(0, S_len); + shares[i].contents += get_byte(1, S_len); + } + + // Choose sequential values for X starting from 1 + for(byte i = 0; i != N; ++i) + shares[i].contents.push_back(i+1); + + // secret = S || H(S) + SecureVector secret(S, S_len); + secret += hash.process(S, S_len); + + for(size_t i = 0; i != secret.size(); ++i) + { + std::vector coefficients(M-1); + rng.randomize(&coefficients[0], coefficients.size()); + + for(byte j = 0; j != N; ++j) + { + const byte X = j + 1; + + byte sum = secret[i]; + byte X_i = X; + + for(size_t k = 0; k != coefficients.size(); ++k) + { + sum ^= gfp_mul(X_i, coefficients[k]); + X_i = gfp_mul(X_i, X); + } + + shares[j].contents.push_back(sum); + } + } + + return shares; + } + +SecureVector +RTSS_Share::reconstruct(const std::vector& shares) + { + const size_t RTSS_HEADER_SIZE = 20; + + for(size_t i = 0; i != shares.size(); ++i) + { + if(shares[i].size() != shares[0].size()) + throw Decoding_Error("Different sized RTSS shares detected"); + if(shares[i].share_id() == 0) + throw Decoding_Error("Invalid (id = 0) RTSS share detected"); + if(shares[i].size() < RTSS_HEADER_SIZE) + throw Decoding_Error("Missing or malformed RTSS header"); + + if(!same_mem(&shares[0].contents[0], + &shares[i].contents[0], RTSS_HEADER_SIZE)) + throw Decoding_Error("Different RTSS headers detected"); + } + + if(shares.size() < shares[0].contents[17]) + throw Decoding_Error("Insufficient shares to do TSS reconstruction"); + + u16bit secret_len = make_u16bit(shares[0].contents[18], + shares[0].contents[19]); + + byte hash_id = shares[0].contents[16]; + + std::unique_ptr hash(get_rtss_hash_by_id(hash_id)); + + if(shares[0].size() != secret_len + hash->output_length() + RTSS_HEADER_SIZE + 1) + throw Decoding_Error("Bad RTSS length field in header"); + + std::vector V(shares.size()); + SecureVector secret; + + for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) + { + for(size_t j = 0; j != V.size(); ++j) + V[j] = shares[j].contents[i]; + + byte r = 0; + for(size_t k = 0; k != shares.size(); ++k) + { + // L_i function: + byte r2 = 1; + for(size_t l = 0; l != shares.size(); ++l) + { + if(k == l) + continue; + + byte share_k = shares[k].share_id(); + byte share_l = shares[l].share_id(); + + if(share_k == share_l) + throw Decoding_Error("Duplicate shares found in RTSS recovery"); + + byte div = RTSS_EXP[(255 + + RTSS_LOG[share_l] - + RTSS_LOG[share_k ^ share_l]) % 255]; + + r2 = gfp_mul(r2, div); + } + + r ^= gfp_mul(V[k], r2); + } + secret.push_back(r); + } + + if(secret.size() != secret_len + hash->output_length()) + throw Decoding_Error("Bad length in RTSS output"); + + hash->update(&secret[0], secret_len); + SecureVector hash_check = hash->final(); + + if(!same_mem(&hash_check[0], + &secret[secret_len], hash->output_length())) + throw Decoding_Error("RTSS hash check failed"); + + return SecureVector(&secret[0], secret_len); + } + +} +/* +* Core Engine +* (C) 1999-2007,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_ECB) +#endif + +#if defined(BOTAN_HAS_CBC) +#endif + +#if defined(BOTAN_HAS_CTS) +#endif + +#if defined(BOTAN_HAS_CFB) +#endif + +#if defined(BOTAN_HAS_OFB) +#endif + +#if defined(BOTAN_HAS_CTR_BE) +#endif + +#if defined(BOTAN_HAS_EAX) +#endif + +#if defined(BOTAN_HAS_XTS) +#endif + +namespace Botan { + +namespace { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec, + const std::string& def_if_empty) + { +#if defined(BOTAN_HAS_CIPHER_MODE_PADDING) + if(algo_spec == "NoPadding" || (algo_spec == "" && def_if_empty == "NoPadding")) + return new Null_Padding; + + if(algo_spec == "PKCS7" || (algo_spec == "" && def_if_empty == "PKCS7")) + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} + +Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, + Cipher_Dir direction, + const std::string& mode, + const std::string& padding) + { +#if defined(BOTAN_HAS_OFB) + if(mode == "OFB") + return new StreamCipher_Filter(new OFB(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_CTR_BE) + if(mode == "CTR-BE") + return new StreamCipher_Filter(new CTR_BE(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_ECB) + if(mode == "ECB" || mode == "") + { + if(direction == ENCRYPTION) + return new ECB_Encryption(block_cipher->clone(), + get_bc_pad(padding, "NoPadding")); + else + return new ECB_Decryption(block_cipher->clone(), + get_bc_pad(padding, "NoPadding")); + } +#endif + + if(mode == "CBC") + { + if(padding == "CTS") + { +#if defined(BOTAN_HAS_CTS) + if(direction == ENCRYPTION) + return new CTS_Encryption(block_cipher->clone()); + else + return new CTS_Decryption(block_cipher->clone()); +#else + return 0; +#endif + } + +#if defined(BOTAN_HAS_CBC) + if(direction == ENCRYPTION) + return new CBC_Encryption(block_cipher->clone(), + get_bc_pad(padding, "PKCS7")); + else + return new CBC_Decryption(block_cipher->clone(), + get_bc_pad(padding, "PKCS7")); +#else + return 0; +#endif + } + +#if defined(BOTAN_HAS_XTS) + if(mode == "XTS") + { + if(direction == ENCRYPTION) + return new XTS_Encryption(block_cipher->clone()); + else + return new XTS_Decryption(block_cipher->clone()); + } +#endif + + if(mode.find("CFB") != std::string::npos || + mode.find("EAX") != std::string::npos) + { + size_t bits = 0; + + std::vector algo_info = parse_algorithm_name(mode); + std::string mode_name = algo_info[0]; + if(algo_info.size() == 1) + bits = 8 * block_cipher->block_size(); + else if(algo_info.size() == 2) + bits = to_u32bit(algo_info[1]); + else + return 0; + +#if defined(BOTAN_HAS_CFB) + if(mode_name == "CFB") + { + if(direction == ENCRYPTION) + return new CFB_Encryption(block_cipher->clone(), bits); + else + return new CFB_Decryption(block_cipher->clone(), bits); + } +#endif + +#if defined(BOTAN_HAS_EAX) + if(mode_name == "EAX") + { + if(direction == ENCRYPTION) + return new EAX_Encryption(block_cipher->clone(), bits); + else + return new EAX_Decryption(block_cipher->clone(), bits); + } +#endif + } + + return 0; + } + +/* +* Get a cipher object +*/ +Keyed_Filter* Core_Engine::get_cipher(const std::string& algo_spec, + Cipher_Dir direction, + Algorithm_Factory& af) + { + std::vector algo_parts = split_on(algo_spec, '/'); + if(algo_parts.empty()) + throw Invalid_Algorithm_Name(algo_spec); + + const std::string cipher_name = algo_parts[0]; + + // check if it is a stream cipher first (easy case) + const StreamCipher* stream_cipher = af.prototype_stream_cipher(cipher_name); + if(stream_cipher) + return new StreamCipher_Filter(stream_cipher->clone()); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_name); + if(!block_cipher) + return 0; + + if(algo_parts.size() >= 4) + return 0; // 4 part mode, not something we know about + + if(algo_parts.size() < 2) + throw Lookup_Error("Cipher specification '" + algo_spec + + "' is missing mode identifier"); + + std::string mode = algo_parts[1]; + + std::string padding; + if(algo_parts.size() == 3) + padding = algo_parts[2]; + else + padding = (mode == "CBC") ? "PKCS7" : "NoPadding"; + + if(mode == "ECB" && padding == "CTS") + return 0; + else if((mode != "CBC" && mode != "ECB") && padding != "NoPadding") + throw Invalid_Algorithm_Name(algo_spec); + + Keyed_Filter* filt = get_cipher_mode(block_cipher, direction, mode, padding); + if(filt) + return filt; + + throw Algorithm_Not_Found(cipher_name + "/" + mode + "/" + padding); + } + +} +/* +* PK Operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_RSA) +#endif + +#if defined(BOTAN_HAS_RW) +#endif + +#if defined(BOTAN_HAS_DSA) +#endif + +#if defined(BOTAN_HAS_ECDSA) +#endif + +#if defined(BOTAN_HAS_ELGAMAL) +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +#endif + +#if defined(BOTAN_HAS_ECDH) +#endif + +namespace Botan { + +PK_Ops::Encryption* +Core_Engine::get_encryption_op(const Public_Key& key) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PublicKey* s = dynamic_cast(&key)) + return new ElGamal_Encryption_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Decryption* +Core_Engine::get_decryption_op(const Private_Key& key) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PrivateKey* s = dynamic_cast(&key)) + return new ElGamal_Decryption_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Key_Agreement* +Core_Engine::get_key_agreement_op(const Private_Key& key) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast(&key)) + return new DH_KA_Operation(*dh); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(const ECDH_PrivateKey* ecdh = dynamic_cast(&key)) + return new ECDH_KA_Operation(*ecdh); +#endif + + return 0; + } + +PK_Ops::Signature* +Core_Engine::get_signature_op(const Private_Key& key) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast(&key)) + return new RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PrivateKey* s = dynamic_cast(&key)) + return new RW_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast(&key)) + return new DSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PrivateKey* s = dynamic_cast(&key)) + return new ECDSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PrivateKey* s = + dynamic_cast(&key)) + return new GOST_3410_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PrivateKey* s = dynamic_cast(&key)) + return new NR_Signature_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Verification* +Core_Engine::get_verify_op(const Public_Key& key) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PublicKey* s = dynamic_cast(&key)) + return new RW_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast(&key)) + return new DSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PublicKey* s = dynamic_cast(&key)) + return new ECDSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PublicKey* s = + dynamic_cast(&key)) + return new GOST_3410_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PublicKey* s = dynamic_cast(&key)) + return new NR_Verification_Operation(*s); +#endif + + return 0; + } + +} +/* +* Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Choose a modular exponentation algorithm +*/ +Modular_Exponentiator* +Core_Engine::mod_exp(const BigInt& n, Power_Mod::Usage_Hints hints) const + { + if(n.is_odd()) + return new Montgomery_Exponentiator(n, hints); + return new Fixed_Window_Exponentiator(n, hints); + } + +} +/* +* Block Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_AES) +#endif + +#if defined(BOTAN_HAS_BLOWFISH) +#endif + +#if defined(BOTAN_HAS_CAMELLIA) +#endif + +#if defined(BOTAN_HAS_CAST) +#endif + +#if defined(BOTAN_HAS_CASCADE) +#endif + +#if defined(BOTAN_HAS_DES) +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) +#endif + +#if defined(BOTAN_HAS_IDEA) +#endif + +#if defined(BOTAN_HAS_KASUMI) +#endif + +#if defined(BOTAN_HAS_LION) +#endif + +#if defined(BOTAN_HAS_LUBY_RACKOFF) +#endif + +#if defined(BOTAN_HAS_MARS) +#endif + +#if defined(BOTAN_HAS_MISTY1) +#endif + +#if defined(BOTAN_HAS_NOEKEON) +#endif + +#if defined(BOTAN_HAS_RC2) +#endif + +#if defined(BOTAN_HAS_RC5) +#endif + +#if defined(BOTAN_HAS_RC6) +#endif + +#if defined(BOTAN_HAS_SAFER) +#endif + +#if defined(BOTAN_HAS_SEED) +#endif + +#if defined(BOTAN_HAS_SERPENT) +#endif + +#if defined(BOTAN_HAS_SKIPJACK) +#endif + +#if defined(BOTAN_HAS_SQUARE) +#endif + +#if defined(BOTAN_HAS_TEA) +#endif + +#if defined(BOTAN_HAS_TWOFISH) +#endif + +#if defined(BOTAN_HAS_XTEA) +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +BlockCipher* Core_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_AES) + if(request.algo_name() == "AES-128") + return new AES_128; + if(request.algo_name() == "AES-192") + return new AES_192; + if(request.algo_name() == "AES-256") + return new AES_256; +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + if(request.algo_name() == "Blowfish") + return new Blowfish; +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + if(request.algo_name() == "Camellia-128") + return new Camellia_128; + if(request.algo_name() == "Camellia-192") + return new Camellia_192; + if(request.algo_name() == "Camellia-256") + return new Camellia_256; +#endif + +#if defined(BOTAN_HAS_CAST) + if(request.algo_name() == "CAST-128") + return new CAST_128; + if(request.algo_name() == "CAST-256") + return new CAST_256; +#endif + +#if defined(BOTAN_HAS_DES) + if(request.algo_name() == "DES") + return new DES; + if(request.algo_name() == "DESX") + return new DESX; + if(request.algo_name() == "TripleDES") + return new TripleDES; +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + if(request.algo_name() == "GOST-28147-89") + return new GOST_28147_89(request.arg(0, "R3411_94_TestParam")); +#endif + +#if defined(BOTAN_HAS_IDEA) + if(request.algo_name() == "IDEA") + return new IDEA; +#endif + +#if defined(BOTAN_HAS_KASUMI) + if(request.algo_name() == "KASUMI") + return new KASUMI; +#endif + +#if defined(BOTAN_HAS_MARS) + if(request.algo_name() == "MARS") + return new MARS; +#endif + +#if defined(BOTAN_HAS_MISTY1) + if(request.algo_name() == "MISTY1") + return new MISTY1(request.arg_as_integer(0, 8)); +#endif + +#if defined(BOTAN_HAS_NOEKEON) + if(request.algo_name() == "Noekeon") + return new Noekeon; +#endif + +#if defined(BOTAN_HAS_RC2) + if(request.algo_name() == "RC2") + return new RC2; +#endif + +#if defined(BOTAN_HAS_RC5) + if(request.algo_name() == "RC5") + return new RC5(request.arg_as_integer(0, 12)); +#endif + +#if defined(BOTAN_HAS_RC6) + if(request.algo_name() == "RC6") + return new RC6; +#endif + +#if defined(BOTAN_HAS_SAFER) + if(request.algo_name() == "SAFER-SK") + return new SAFER_SK(request.arg_as_integer(0, 10)); +#endif + +#if defined(BOTAN_HAS_SEED) + if(request.algo_name() == "SEED") + return new SEED; +#endif + +#if defined(BOTAN_HAS_SERPENT) + if(request.algo_name() == "Serpent") + return new Serpent; +#endif + +#if defined(BOTAN_HAS_SKIPJACK) + if(request.algo_name() == "Skipjack") + return new Skipjack; +#endif + +#if defined(BOTAN_HAS_SQUARE) + if(request.algo_name() == "Square") + return new Square; +#endif + +#if defined(BOTAN_HAS_TEA) + if(request.algo_name() == "TEA") + return new TEA; +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(request.algo_name() == "Twofish") + return new Twofish; +#endif + +#if defined(BOTAN_HAS_XTEA) + if(request.algo_name() == "XTEA") + return new XTEA; +#endif + +#if defined(BOTAN_HAS_LUBY_RACKOFF) + if(request.algo_name() == "Luby-Rackoff" && request.arg_count() == 1) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(0)); + + if(hash) + return new LubyRackoff(hash->clone()); + } +#endif + +#if defined(BOTAN_HAS_CASCADE) + if(request.algo_name() == "Cascade" && request.arg_count() == 2) + { + const BlockCipher* c1 = af.prototype_block_cipher(request.arg(0)); + const BlockCipher* c2 = af.prototype_block_cipher(request.arg(1)); + + if(c1 && c2) + return new Cascade_Cipher(c1->clone(), c2->clone()); + } +#endif + +#if defined(BOTAN_HAS_LION) + if(request.algo_name() == "Lion" && request.arg_count_between(2, 3)) + { + const size_t block_size = request.arg_as_integer(2, 1024); + + const HashFunction* hash = + af.prototype_hash_function(request.arg(0)); + + const StreamCipher* stream_cipher = + af.prototype_stream_cipher(request.arg(1)); + + if(!hash || !stream_cipher) + return 0; + + return new Lion(hash->clone(), stream_cipher->clone(), block_size); + } +#endif + + return 0; + } + +} +/* +* Hash Algorithms Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_ADLER32) +#endif + +#if defined(BOTAN_HAS_CRC24) +#endif + +#if defined(BOTAN_HAS_CRC32) +#endif + +#if defined(BOTAN_HAS_BMW_512) +#endif + +#if defined(BOTAN_HAS_GOST_34_11) +#endif + +#if defined(BOTAN_HAS_HAS_160) +#endif + +#if defined(BOTAN_HAS_KECCAK) +#endif + +#if defined(BOTAN_HAS_MD2) +#endif + +#if defined(BOTAN_HAS_MD4) +#endif + +#if defined(BOTAN_HAS_MD5) +#endif + +#if defined(BOTAN_HAS_RIPEMD_128) +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) +#endif + +#if defined(BOTAN_HAS_SHA1) +#endif + +#if defined(BOTAN_HAS_SHA2_32) +#endif + +#if defined(BOTAN_HAS_SHA2_64) +#endif + +#if defined(BOTAN_HAS_SKEIN_512) +#endif + +#if defined(BOTAN_HAS_TIGER) +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) +#endif + +#if defined(BOTAN_HAS_COMB4P) +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +HashFunction* Core_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_ADLER32) + if(request.algo_name() == "Adler32") + return new Adler32; +#endif + +#if defined(BOTAN_HAS_CRC24) + if(request.algo_name() == "CRC24") + return new CRC24; +#endif + +#if defined(BOTAN_HAS_CRC32) + if(request.algo_name() == "CRC32") + return new CRC32; +#endif + +#if defined(BOTAN_HAS_BMW_512) + if(request.algo_name() == "BMW-512") + return new BMW_512; +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + if(request.algo_name() == "GOST-34.11") + return new GOST_34_11; +#endif + +#if defined(BOTAN_HAS_HAS_160) + if(request.algo_name() == "HAS-160") + return new HAS_160; +#endif + +#if defined(BOTAN_HAS_KECCAK) + if(request.algo_name() == "Keccak-1600") + return new Keccak_1600(request.arg_as_integer(0, 512)); +#endif + +#if defined(BOTAN_HAS_MD2) + if(request.algo_name() == "MD2") + return new MD2; +#endif + +#if defined(BOTAN_HAS_MD4) + if(request.algo_name() == "MD4") + return new MD4; +#endif + +#if defined(BOTAN_HAS_MD5) + if(request.algo_name() == "MD5") + return new MD5; +#endif + +#if defined(BOTAN_HAS_RIPEMD_128) + if(request.algo_name() == "RIPEMD-128") + return new RIPEMD_128; +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + if(request.algo_name() == "RIPEMD-160") + return new RIPEMD_160; +#endif + +#if defined(BOTAN_HAS_SHA1) + if(request.algo_name() == "SHA-160") + return new SHA_160; +#endif + +#if defined(BOTAN_HAS_SHA2_32) + if(request.algo_name() == "SHA-224") + return new SHA_224; + if(request.algo_name() == "SHA-256") + return new SHA_256; +#endif + +#if defined(BOTAN_HAS_SHA2_64) + if(request.algo_name() == "SHA-384") + return new SHA_384; + if(request.algo_name() == "SHA-512") + return new SHA_512; +#endif + +#if defined(BOTAN_HAS_TIGER) + if(request.algo_name() == "Tiger") + return new Tiger(request.arg_as_integer(0, 24), // hash output + request.arg_as_integer(1, 3)); // # passes +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + if(request.algo_name() == "Skein-512") + return new Skein_512(request.arg_as_integer(0, 512), + request.arg(1, "")); +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(request.algo_name() == "Whirlpool") + return new Whirlpool; +#endif + +#if defined(BOTAN_HAS_COMB4P) + if(request.algo_name() == "Comb4P" && request.arg_count() == 2) + { + const HashFunction* h1 = af.prototype_hash_function(request.arg(0)); + const HashFunction* h2 = af.prototype_hash_function(request.arg(1)); + + if(h1 && h2) + return new Comb4P(h1->clone(), h2->clone()); + } +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + + if(request.algo_name() == "Parallel") + { + std::vector hash_prototypes; + + /* First pass, just get the prototypes (no memory allocation). Then + if all were found, replace each prototype with a newly created clone + */ + for(size_t i = 0; i != request.arg_count(); ++i) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(i)); + if(!hash) + return 0; + + hash_prototypes.push_back(hash); + } + + std::vector hashes; + for(size_t i = 0; i != hash_prototypes.size(); ++i) + hashes.push_back(hash_prototypes[i]->clone()); + + return new Parallel(hashes); + } + +#endif + + return 0; + } + +} +/* +* MAC Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_CBC_MAC) +#endif + +#if defined(BOTAN_HAS_CMAC) +#endif + +#if defined(BOTAN_HAS_HMAC) +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +MessageAuthenticationCode* +Core_Engine::find_mac(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_CBC_MAC) + if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1) + return new CBC_MAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_CMAC) + if(request.algo_name() == "CMAC" && request.arg_count() == 1) + return new CMAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_HMAC) + if(request.algo_name() == "HMAC" && request.arg_count() == 1) + return new HMAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) + if(request.algo_name() == "SSL3-MAC" && request.arg_count() == 1) + return new SSL3_MAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(request.algo_name() == "X9.19-MAC" && request.arg_count() == 0) + return new ANSI_X919_MAC(af.make_block_cipher("DES")); +#endif + + return 0; + } + +} +/* +* PBKDF Lookup +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_PBKDF1) +#endif + +#if defined(BOTAN_HAS_PBKDF2) +#endif + +#if defined(BOTAN_HAS_PGPS2K) +#endif + +namespace Botan { + +PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_PBKDF1) + if(algo_spec.algo_name() == "PBKDF1" && algo_spec.arg_count() == 1) + return new PKCS5_PBKDF1(af.make_hash_function(algo_spec.arg(0))); +#endif + +#if defined(BOTAN_HAS_PBKDF2) + if(algo_spec.algo_name() == "PBKDF2" && algo_spec.arg_count() == 1) + { + if(const MessageAuthenticationCode* mac_proto = af.prototype_mac(algo_spec.arg(0))) + return new PKCS5_PBKDF2(mac_proto->clone()); + + return new PKCS5_PBKDF2(af.make_mac("HMAC(" + algo_spec.arg(0) + ")")); + } +#endif + +#if defined(BOTAN_HAS_PGPS2K) + if(algo_spec.algo_name() == "OpenPGP-S2K" && algo_spec.arg_count() == 1) + return new OpenPGP_S2K(af.make_hash_function(algo_spec.arg(0))); +#endif + + return 0; + } + +} +/* +* Stream Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_ARC4) +#endif + +#if defined(BOTAN_HAS_SALSA20) +#endif + +#if defined(BOTAN_HAS_TURING) +#endif + +#if defined(BOTAN_HAS_WID_WAKE) +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +StreamCipher* +Core_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_ARC4) + if(request.algo_name() == "ARC4") + return new ARC4(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new ARC4(768); +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(request.algo_name() == "Salsa20") + return new Salsa20; +#endif + +#if defined(BOTAN_HAS_TURING) + if(request.algo_name() == "Turing") + return new Turing; +#endif + +#if defined(BOTAN_HAS_WID_WAKE) + if(request.algo_name() == "WiderWake4+1-BE") + return new WiderWake_41_BE; +#endif + + return 0; + } + +} +/** +* Dynamically Loaded Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +extern "C" { + typedef Engine* (*creator_func)(void); + typedef u32bit (*module_version_func)(void); +} + +} + +Dynamically_Loaded_Engine::Dynamically_Loaded_Engine( + const std::string& library_path) : + engine(0) + { + lib = new Dynamically_Loaded_Library(library_path); + + try + { + module_version_func get_version = + lib->resolve("module_version"); + + const u32bit mod_version = get_version(); + + if(mod_version != 20101003) + throw std::runtime_error("Incompatible version in " + + library_path + " of " + + to_string(mod_version)); + + creator_func creator = + lib->resolve("create_engine"); + + engine = creator(); + + if(!engine) + throw std::runtime_error("Creator function in " + + library_path + " failed"); + } + catch(...) + { + delete lib; + lib = 0; + throw; + } + } + +Dynamically_Loaded_Engine::~Dynamically_Loaded_Engine() + { + delete engine; + delete lib; + } + +} +/* +* Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +BlockCipher* +Engine::find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return 0; + } + +StreamCipher* +Engine::find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return 0; + } + +HashFunction* +Engine::find_hash(const SCAN_Name&, + Algorithm_Factory&) const + { + return 0; + } + +MessageAuthenticationCode* +Engine::find_mac(const SCAN_Name&, + Algorithm_Factory&) const + { + return 0; + } + +PBKDF* +Engine::find_pbkdf(const SCAN_Name&, + Algorithm_Factory&) const + { + return 0; + } + +Modular_Exponentiator* +Engine::mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const + { + return 0; + } + +Keyed_Filter* Engine::get_cipher(const std::string&, + Cipher_Dir, + Algorithm_Factory&) + { + return 0; + } + +PK_Ops::Key_Agreement* +Engine::get_key_agreement_op(const Private_Key&) const + { + return 0; + } + +PK_Ops::Signature* +Engine::get_signature_op(const Private_Key&) const + { + return 0; + } + +PK_Ops::Verification* +Engine::get_verify_op(const Public_Key&) const + { + return 0; + } + +PK_Ops::Encryption* +Engine::get_encryption_op(const Public_Key&) const + { + return 0; + } + +PK_Ops::Decryption* +Engine::get_decryption_op(const Private_Key&) const + { + return 0; + } + +} +/* +* SIMD Engine +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_AES_SSSE3) +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) +#endif + +namespace Botan { + +BlockCipher* +SIMD_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_AES_SSSE3) + if(request.algo_name() == "AES-128" && CPUID::has_ssse3()) + return new AES_128_SSSE3; + if(request.algo_name() == "AES-192" && CPUID::has_ssse3()) + return new AES_192_SSSE3; + if(request.algo_name() == "AES-256" && CPUID::has_ssse3()) + return new AES_256_SSSE3; +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) + if(request.algo_name() == "IDEA" && CPUID::has_sse2()) + return new IDEA_SSE2; +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(request.algo_name() == "Noekeon" && SIMD_32::enabled()) + return new Noekeon_SIMD; +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(request.algo_name() == "Serpent" && SIMD_32::enabled()) + return new Serpent_SIMD; +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) + if(request.algo_name() == "XTEA" && SIMD_32::enabled()) + return new XTEA_SIMD; +#endif + + return 0; + } + +HashFunction* +SIMD_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_SHA1_SSE2) + if(request.algo_name() == "SHA-160" && CPUID::has_sse2()) + return new SHA_160_SSE2; +#else + Q_UNUSED(request); +#endif + + return 0; + } + +} + +#ifdef Q_OS_WIN +/* +* Win32 CryptoAPI EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +class CSP_Handle + { + public: + CSP_Handle(u64bit capi_provider) + { + valid = false; + DWORD prov_type = (DWORD)capi_provider; + + if(CryptAcquireContext(&handle, 0, 0, + prov_type, CRYPT_VERIFYCONTEXT)) + valid = true; + } + + ~CSP_Handle() + { + if(is_valid()) + CryptReleaseContext(handle, 0); + } + + size_t gen_random(byte out[], size_t n) const + { + if(is_valid() && CryptGenRandom(handle, static_cast(n), out)) + return n; + return 0; + } + + bool is_valid() const { return valid; } + + HCRYPTPROV get_handle() const { return handle; } + private: + HCRYPTPROV handle; + bool valid; + }; + +} + +/* +* Gather Entropy from Win32 CAPI +*/ +void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum) + { + MemoryRegion& io_buffer = accum.get_io_buffer(32); + + for(size_t i = 0; i != prov_types.size(); ++i) + { + CSP_Handle csp(prov_types[i]); + + size_t got = csp.gen_random(&io_buffer[0], io_buffer.size()); + + if(got) + { + accum.add(&io_buffer[0], io_buffer.size(), 6); + break; + } + } + } + +/* +* Win32_Capi_Entropysource Constructor +*/ +Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) + { + std::vector capi_provs = split_on(provs, ':'); + + for(size_t i = 0; i != capi_provs.size(); ++i) + { + if(capi_provs[i] == "RSA_FULL") prov_types.push_back(PROV_RSA_FULL); + if(capi_provs[i] == "INTEL_SEC") prov_types.push_back(PROV_INTEL_SEC); + if(capi_provs[i] == "FORTEZZA") prov_types.push_back(PROV_FORTEZZA); + if(capi_provs[i] == "RNG") prov_types.push_back(PROV_RNG); + } + + if(prov_types.size() == 0) + prov_types.push_back(PROV_RSA_FULL); + } + +} +#endif + +#ifdef Q_OS_UNIX +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +Close the device, if open +*/ +void Device_EntropySource::Device_Reader::close() + { + if(fd > 0) { ::close(fd); fd = -1; } + } + +/** +Read bytes from a device file +*/ +size_t Device_EntropySource::Device_Reader::get(byte out[], size_t length, + size_t ms_wait_time) + { + if(fd < 0) + return 0; + + if(fd >= FD_SETSIZE) + return 0; + + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(fd, &read_set); + + struct ::timeval timeout; + + timeout.tv_sec = (ms_wait_time / 1000); + timeout.tv_usec = (ms_wait_time % 1000) * 1000; + + if(::select(fd + 1, &read_set, 0, 0, &timeout) < 0) + return 0; + + if(!(FD_ISSET(fd, &read_set))) + return 0; + + const ssize_t got = ::read(fd, out, length); + if(got <= 0) + return 0; + + return static_cast(got); + } + +/** +Attempt to open a device +*/ +Device_EntropySource::Device_Reader::fd_type +Device_EntropySource::Device_Reader::open(const std::string& pathname) + { +#ifndef O_NONBLOCK + #define O_NONBLOCK 0 +#endif + +#ifndef O_NOCTTY + #define O_NOCTTY 0 +#endif + + const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; + return ::open(pathname.c_str(), flags); + } + +/** +Device_EntropySource constructor +Open a file descriptor to each (available) device in fsnames +*/ +Device_EntropySource::Device_EntropySource( + const std::vector& fsnames) + { + for(size_t i = 0; i != fsnames.size(); ++i) + { + Device_Reader::fd_type fd = Device_Reader::open(fsnames[i]); + if(fd > 0) + devices.push_back(Device_Reader(fd)); + } + } + +/** +Device_EntropySource destructor: close all open devices +*/ +Device_EntropySource::~Device_EntropySource() + { + for(size_t i = 0; i != devices.size(); ++i) + devices[i].close(); + } + +/** +* Gather entropy from a RNG device +*/ +void Device_EntropySource::poll(Entropy_Accumulator& accum) + { + const size_t ENTROPY_BITS_PER_BYTE = 7; + + const size_t go_get = std::min( + accum.desired_remaining_bits() / ENTROPY_BITS_PER_BYTE, 32); + + const size_t read_wait_ms = std::max(go_get, 100); + MemoryRegion& io_buffer = accum.get_io_buffer(go_get); + + for(size_t i = 0; i != devices.size(); ++i) + { + size_t got = devices[i].get(&io_buffer[0], io_buffer.size(), + read_wait_ms); + + if(got) + { + accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE); + break; + } + } + } + +} + +/* +* EGD EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifndef PF_LOCAL + #define PF_LOCAL PF_UNIX +#endif + +namespace Botan { + +EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) : + socket_path(path), m_fd(-1) + { + } + +/** +* Attempt a connection to an EGD/PRNGD socket +*/ +int EGD_EntropySource::EGD_Socket::open_socket(const std::string& path) + { + int fd = ::socket(PF_LOCAL, SOCK_STREAM, 0); + + if(fd >= 0) + { + sockaddr_un addr; + std::memset(&addr, 0, sizeof(addr)); + addr.sun_family = PF_LOCAL; + + if(sizeof(addr.sun_path) < path.length() + 1) + throw std::invalid_argument("EGD socket path is too long"); + + std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path)); + + int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1; + + if(::connect(fd, reinterpret_cast(&addr), len) < 0) + { + ::close(fd); + fd = -1; + } + } + + return fd; + } + +/** +* Attempt to read entropy from EGD +*/ +size_t EGD_EntropySource::EGD_Socket::read(byte outbuf[], size_t length) + { + if(length == 0) + return 0; + + if(m_fd < 0) + { + m_fd = open_socket(socket_path); + if(m_fd < 0) + return 0; + } + + try + { + // 1 == EGD command for non-blocking read + byte egd_read_command[2] = { + 1, static_cast(std::min(length, 255)) }; + + if(::write(m_fd, egd_read_command, 2) != 2) + throw std::runtime_error("Writing entropy read command to EGD failed"); + + byte out_len = 0; + if(::read(m_fd, &out_len, 1) != 1) + throw std::runtime_error("Reading response length from EGD failed"); + + if(out_len > egd_read_command[1]) + throw std::runtime_error("Bogus length field received from EGD"); + + ssize_t count = ::read(m_fd, outbuf, out_len); + + if(count != out_len) + throw std::runtime_error("Reading entropy result from EGD failed"); + + return static_cast(count); + } + catch(std::exception) + { + this->close(); + // Will attempt to reopen next poll + } + + return 0; + } + +void EGD_EntropySource::EGD_Socket::close() + { + if(m_fd > 0) + { + ::close(m_fd); + m_fd = -1; + } + } + +/** +* EGD_EntropySource constructor +*/ +EGD_EntropySource::EGD_EntropySource(const std::vector& paths) + { + for(size_t i = 0; i != paths.size(); ++i) + sockets.push_back(EGD_Socket(paths[i])); + } + +EGD_EntropySource::~EGD_EntropySource() + { + for(size_t i = 0; i != sockets.size(); ++i) + sockets[i].close(); + sockets.clear(); + } + +/** +* Gather Entropy from EGD +*/ +void EGD_EntropySource::poll(Entropy_Accumulator& accum) + { + size_t go_get = std::min(accum.desired_remaining_bits() / 8, 32); + + MemoryRegion& io_buffer = accum.get_io_buffer(go_get); + + for(size_t i = 0; i != sockets.size(); ++i) + { + size_t got = sockets[i].read(&io_buffer[0], io_buffer.size()); + + if(got) + { + accum.add(&io_buffer[0], got, 6); + break; + } + } + } + +} +#endif + +/* +* High Resolution Timestamp Entropy Source +* (C) 1999-2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_TARGET_OS_IS_WINDOWS) + #include +#endif + +namespace Botan { + +/* +* Get the timestamp +*/ +void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum) + { + // If Windows, grab the Performance Counter (usually TSC or PIT) +#if defined(BOTAN_TARGET_OS_IS_WINDOWS) + { + LARGE_INTEGER tv; + ::QueryPerformanceCounter(&tv); + accum.add(tv.QuadPart, 0); + } +#endif + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + +#define CLOCK_POLL(src) \ + do { \ + struct timespec ts; \ + clock_gettime(src, &ts); \ + accum.add(&ts, sizeof(ts), 0); \ + } while(0) + +#if defined(CLOCK_REALTIME) + CLOCK_POLL(CLOCK_REALTIME); +#endif + +#if defined(CLOCK_MONOTONIC) + CLOCK_POLL(CLOCK_MONOTONIC); +#endif + +#if defined(CLOCK_MONOTONIC_RAW) + CLOCK_POLL(CLOCK_MONOTONIC_RAW); +#endif + +#if defined(CLOCK_PROCESS_CPUTIME_ID) + CLOCK_POLL(CLOCK_PROCESS_CPUTIME_ID); +#endif + +#if defined(CLOCK_THREAD_CPUTIME_ID) + CLOCK_POLL(CLOCK_THREAD_CPUTIME_ID); +#endif + +#undef CLOCK_POLL + +#endif + +#if BOTAN_USE_GCC_INLINE_ASM + + u64bit rtc = 0; + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + if(CPUID::has_rdtsc()) // not availble on all x86 CPUs + { + u32bit rtc_low = 0, rtc_high = 0; + asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); + rtc = (static_cast(rtc_high) << 32) | rtc_low; + } + +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + u32bit rtc_low = 0, rtc_high = 0; + asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low)); + rtc = (static_cast(rtc_high) << 32) | rtc_low; + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + asm volatile("rpcc %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) + asm volatile("rd %%tick, %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + asm volatile("mov %0=ar.itc" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_S390X) + asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); + +#elif defined(BOTAN_TARGET_ARCH_IS_HPPA) + asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? + +#endif + + // Don't count the timestamp as contributing entropy + accum.add(rtc, 0); + +#endif + } + +} + +#ifdef Q_OS_UNIX +/* +* FTW EntropySource +* (C) 1999-2008,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +#ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309 +#endif + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Returns file descriptors. Until it doesn't +*/ +class File_Descriptor_Source + { + public: + /** + * @return next file descriptor, or -1 if done + */ + virtual int next_fd() = 0; + + virtual ~File_Descriptor_Source() {} + }; + +namespace { + +class Directory_Walker : public File_Descriptor_Source + { + public: + Directory_Walker(const std::string& root) : + m_cur_dir(std::make_pair(0, "")) + { + if(DIR* root_dir = ::opendir(root.c_str())) + m_cur_dir = std::make_pair(root_dir, root); + } + + ~Directory_Walker() + { + if(m_cur_dir.first) + ::closedir(m_cur_dir.first); + } + + int next_fd(); + private: + void add_directory(const std::string& dirname) + { + m_dirlist.push_back(dirname); + } + + std::pair get_next_dirent(); + + std::pair m_cur_dir; + std::deque m_dirlist; + }; + +std::pair Directory_Walker::get_next_dirent() + { + while(m_cur_dir.first) + { + struct dirent* dir = ::readdir(m_cur_dir.first); + + if(dir) + return std::make_pair(dir, m_cur_dir.second); + + ::closedir(m_cur_dir.first); + m_cur_dir = std::make_pair(0, ""); + + while(!m_dirlist.empty() && m_cur_dir.first == 0) + { + const std::string next_dir_name = m_dirlist[0]; + m_dirlist.pop_front(); + + if(DIR* next_dir = ::opendir(next_dir_name.c_str())) + m_cur_dir = std::make_pair(next_dir, next_dir_name); + } + } + + return std::make_pair(0, ""); // nothing left + } + +int Directory_Walker::next_fd() + { + while(true) + { + std::pair entry = get_next_dirent(); + + if(!entry.first) + break; // no more dirs + + const std::string filename = entry.first->d_name; + + if(filename == "." || filename == "..") + continue; + + const std::string full_path = entry.second + '/' + filename; + + struct stat stat_buf; + if(::lstat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + { + add_directory(full_path); + } + else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH)) + { + int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY); + + if(fd > 0) + return fd; + } + } + + return -1; + } + +} + +/** +* FTW_EntropySource Constructor +*/ +FTW_EntropySource::FTW_EntropySource(const std::string& p) : path(p) + { + dir = 0; + } + +/** +* FTW_EntropySource Destructor +*/ +FTW_EntropySource::~FTW_EntropySource() + { + delete dir; + } + +void FTW_EntropySource::poll(Entropy_Accumulator& accum) + { + const size_t MAX_FILES_READ_PER_POLL = 2048; + + if(!dir) + dir = new Directory_Walker(path); + + MemoryRegion& io_buffer = accum.get_io_buffer(4096); + + for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i) + { + int fd = dir->next_fd(); + + // If we've exhaused this walk of the directory, halt the poll + if(fd == -1) + { + delete dir; + dir = 0; + break; + } + + ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size()); + ::close(fd); + + if(got > 0) + accum.add(&io_buffer[0], got, .001); + + if(accum.polling_goal_achieved()) + break; + } + } + +} + +/* +* Unix EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* Sort ordering by priority +*/ +bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b) + { + if(a.priority == b.priority) + return (a.name_and_args < b.name_and_args); + + return (a.priority < b.priority); + } + +} + +/** +* Unix_EntropySource Constructor +*/ +Unix_EntropySource::Unix_EntropySource(const std::vector& path) : + PATH(path) + { + std::vector default_sources = get_default_sources(); + add_sources(&default_sources[0], default_sources.size()); + } + +/** +* Add sources to the list +*/ +void Unix_EntropySource::add_sources(const Unix_Program srcs[], size_t count) + { + sources.insert(sources.end(), srcs, srcs + count); + std::sort(sources.begin(), sources.end(), Unix_Program_Cmp); + } + +/** +* Poll for entropy on a generic Unix system, first by grabbing various +* statistics (stat on common files, getrusage, etc), and then, if more +* is required, by exec'ing various programs like uname and rpcinfo and +* reading the output. +*/ +void Unix_EntropySource::poll(Entropy_Accumulator& accum) + { + const char* stat_targets[] = { + "/", + "/tmp", + "/var/tmp", + "/usr", + "/home", + "/etc/passwd", + ".", + "..", + 0 }; + + for(size_t i = 0; stat_targets[i]; i++) + { + struct stat statbuf; + clear_mem(&statbuf, 1); + ::stat(stat_targets[i], &statbuf); + accum.add(&statbuf, sizeof(statbuf), .005); + } + + accum.add(::getpid(), 0); + accum.add(::getppid(), 0); + accum.add(::getuid(), 0); + accum.add(::getgid(), 0); + accum.add(::getpgrp(), 0); + + struct ::rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + accum.add(usage, .005); + + ::getrusage(RUSAGE_CHILDREN, &usage); + accum.add(usage, .005); + + const size_t MINIMAL_WORKING = 16; + + MemoryRegion& io_buffer = accum.get_io_buffer(DEFAULT_BUFFERSIZE); + + for(size_t i = 0; i != sources.size(); i++) + { + DataSource_Command pipe(sources[i].name_and_args, PATH); + + size_t got_from_src = 0; + + while(!pipe.end_of_data()) + { + size_t got_this_loop = pipe.read(&io_buffer[0], io_buffer.size()); + got_from_src += got_this_loop; + + accum.add(&io_buffer[0], got_this_loop, .005); + } + + sources[i].working = (got_from_src >= MINIMAL_WORKING) ? true : false; + + if(accum.polling_goal_achieved()) + break; + } + } + +} +/* +* Unix Command Execution +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* Attempt to execute the command +*/ +void do_exec(const std::vector& arg_list, + const std::vector& paths) + { + const size_t args = arg_list.size() - 1; + + const char* arg1 = (args >= 1) ? arg_list[1].c_str() : 0; + const char* arg2 = (args >= 2) ? arg_list[2].c_str() : 0; + const char* arg3 = (args >= 3) ? arg_list[3].c_str() : 0; + const char* arg4 = (args >= 4) ? arg_list[4].c_str() : 0; + + for(size_t j = 0; j != paths.size(); j++) + { + const std::string full_path = paths[j] + "/" + arg_list[0]; + const char* fsname = full_path.c_str(); + + ::execl(fsname, fsname, arg1, arg2, arg3, arg4, NULL); + } + } + +} + +/** +* Local information about the pipe +*/ +struct pipe_wrapper + { + int fd; + pid_t pid; + + pipe_wrapper(int f, pid_t p) : fd(f), pid(p) {} + ~pipe_wrapper() { ::close(fd); } + }; + +/** +* Read from the pipe +*/ +size_t DataSource_Command::read(byte buf[], size_t length) + { + if(end_of_data()) + return 0; + + fd_set set; + FD_ZERO(&set); + FD_SET(pipe->fd, &set); + + struct ::timeval tv; + tv.tv_sec = 0; + tv.tv_usec = MAX_BLOCK_USECS; + + ssize_t got = 0; + if(::select(pipe->fd + 1, &set, 0, 0, &tv) == 1) + { + if(FD_ISSET(pipe->fd, &set)) + got = ::read(pipe->fd, buf, length); + } + + if(got <= 0) + { + shutdown_pipe(); + return 0; + } + + return static_cast(got); + } + +/** +* Peek at the pipe contents +*/ +size_t DataSource_Command::peek(byte[], size_t, size_t) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Command: Cannot peek when out of data"); + throw Stream_IO_Error("Cannot peek/seek on a command pipe"); + } + +/** +* Check if we reached EOF +*/ +bool DataSource_Command::end_of_data() const + { + return (pipe) ? false : true; + } + +/** +* Return the Unix file descriptor of the pipe +*/ +int DataSource_Command::fd() const + { + if(!pipe) + return -1; + return pipe->fd; + } + +/** +* Return a human-readable ID for this stream +*/ +std::string DataSource_Command::id() const + { + return "Unix command: " + arg_list[0]; + } + +/** +* Create the pipe +*/ +void DataSource_Command::create_pipe(const std::vector& paths) + { + bool found_something = false; + + for(size_t j = 0; j != paths.size(); j++) + { + const std::string full_path = paths[j] + "/" + arg_list[0]; + if(::access(full_path.c_str(), X_OK) == 0) + { + found_something = true; + break; + } + } + + if(!found_something) + return; + + int pipe_fd[2]; + if(::pipe(pipe_fd) != 0) + return; + + pid_t pid = ::fork(); + + if(pid == -1) + { + ::close(pipe_fd[0]); + ::close(pipe_fd[1]); + } + else if(pid > 0) + { + pipe = new pipe_wrapper(pipe_fd[0], pid); + ::close(pipe_fd[1]); + } + else + { + if(dup2(pipe_fd[1], STDOUT_FILENO) == -1) + ::exit(127); + if(close(pipe_fd[0]) != 0 || close(pipe_fd[1]) != 0) + ::exit(127); + if(close(STDERR_FILENO) != 0) + ::exit(127); + + do_exec(arg_list, paths); + ::exit(127); + } + } + +/** +* Shutdown the pipe +*/ +void DataSource_Command::shutdown_pipe() + { + if(pipe) + { + pid_t reaped = waitpid(pipe->pid, 0, WNOHANG); + + if(reaped == 0) + { + kill(pipe->pid, SIGTERM); + + struct ::timeval tv; + tv.tv_sec = 0; + tv.tv_usec = KILL_WAIT; + select(0, 0, 0, 0, &tv); + + reaped = ::waitpid(pipe->pid, 0, WNOHANG); + + if(reaped == 0) + { + ::kill(pipe->pid, SIGKILL); + do + reaped = ::waitpid(pipe->pid, 0, 0); + while(reaped == -1); + } + } + + delete pipe; + pipe = 0; + } + } + +/** +* DataSource_Command Constructor +*/ +DataSource_Command::DataSource_Command(const std::string& prog_and_args, + const std::vector& paths) : + MAX_BLOCK_USECS(100000), KILL_WAIT(10000) + { + arg_list = split_on(prog_and_args, ' '); + + if(arg_list.size() == 0) + throw Invalid_Argument("DataSource_Command: No command given"); + if(arg_list.size() > 5) + throw Invalid_Argument("DataSource_Command: Too many args"); + + pipe = 0; + create_pipe(paths); + } + +/** +* DataSource_Command Destructor +*/ +DataSource_Command::~DataSource_Command() + { + if(!end_of_data()) + shutdown_pipe(); + } + +} +/* +* Program List for Unix_EntropySource +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/** +* Default Commands for Entropy Gathering +*/ +std::vector Unix_EntropySource::get_default_sources() + { + std::vector srcs; + + srcs.push_back(Unix_Program("netstat -in", 1)); + srcs.push_back(Unix_Program("pfstat", 1)); + srcs.push_back(Unix_Program("vmstat -s", 1)); + srcs.push_back(Unix_Program("vmstat", 1)); + + srcs.push_back(Unix_Program("arp -a -n", 2)); + srcs.push_back(Unix_Program("ifconfig -a", 2)); + srcs.push_back(Unix_Program("iostat", 2)); + srcs.push_back(Unix_Program("ipcs -a", 2)); + srcs.push_back(Unix_Program("mpstat", 2)); + srcs.push_back(Unix_Program("netstat -an", 2)); + srcs.push_back(Unix_Program("netstat -s", 2)); + srcs.push_back(Unix_Program("nfsstat", 2)); + srcs.push_back(Unix_Program("portstat", 2)); + srcs.push_back(Unix_Program("procinfo -a", 2)); + srcs.push_back(Unix_Program("pstat -T", 2)); + srcs.push_back(Unix_Program("pstat -s", 2)); + srcs.push_back(Unix_Program("uname -a", 2)); + srcs.push_back(Unix_Program("uptime", 2)); + + srcs.push_back(Unix_Program("listarea", 3)); + srcs.push_back(Unix_Program("listdev", 3)); + srcs.push_back(Unix_Program("ps -A", 3)); + srcs.push_back(Unix_Program("sysinfo", 3)); + + srcs.push_back(Unix_Program("finger", 4)); + srcs.push_back(Unix_Program("mailstats", 4)); + srcs.push_back(Unix_Program("rpcinfo -p localhost", 4)); + srcs.push_back(Unix_Program("who", 4)); + + srcs.push_back(Unix_Program("df -l", 4)); + srcs.push_back(Unix_Program("dmesg", 4)); + srcs.push_back(Unix_Program("last -5", 4)); + srcs.push_back(Unix_Program("ls -alni /proc", 4)); + srcs.push_back(Unix_Program("ls -alni /tmp", 4)); + srcs.push_back(Unix_Program("pstat -f", 4)); + + srcs.push_back(Unix_Program("ps -elf", 5)); + srcs.push_back(Unix_Program("ps aux", 5)); + + srcs.push_back(Unix_Program("lsof -n", 6)); + srcs.push_back(Unix_Program("sar -A", 6)); + + return srcs; + } + +} +#endif + +#ifdef Q_OS_WIN +/* +* Win32 EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/** +* Win32 poll using stats functions including Tooltip32 +*/ +void Win32_EntropySource::poll(Entropy_Accumulator& accum) + { + /* + First query a bunch of basic statistical stuff, though + don't count it for much in terms of contributed entropy. + */ + accum.add(GetTickCount(), 0); + accum.add(GetMessagePos(), 0); + accum.add(GetMessageTime(), 0); + accum.add(GetInputState(), 0); + accum.add(GetCurrentProcessId(), 0); + accum.add(GetCurrentThreadId(), 0); + + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + accum.add(sys_info, 1); + + MEMORYSTATUS mem_info; + GlobalMemoryStatus(&mem_info); + accum.add(mem_info, 1); + + POINT point; + GetCursorPos(&point); + accum.add(point, 1); + + GetCaretPos(&point); + accum.add(point, 1); + + LARGE_INTEGER perf_counter; + QueryPerformanceCounter(&perf_counter); + accum.add(perf_counter, 0); + + /* + Now use the Tooltip library to iterate throug various objects on + the system, including processes, threads, and heap objects. + */ + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + +#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \ + if(!accum.polling_goal_achieved()) \ + { \ + DATA_TYPE info; \ + info.dwSize = sizeof(DATA_TYPE); \ + if(FUNC_FIRST(snapshot, &info)) \ + { \ + do \ + { \ + accum.add(info, 1); \ + } while(FUNC_NEXT(snapshot, &info)); \ + } \ + } + + TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next); + TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next); + TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next); + +#undef TOOLHELP32_ITER + + if(!accum.polling_goal_achieved()) + { + size_t heap_lists_found = 0; + HEAPLIST32 heap_list; + heap_list.dwSize = sizeof(HEAPLIST32); + + const size_t HEAP_LISTS_MAX = 32; + const size_t HEAP_OBJS_PER_LIST = 128; + + if(Heap32ListFirst(snapshot, &heap_list)) + { + do + { + accum.add(heap_list, 1); + + if(++heap_lists_found > HEAP_LISTS_MAX) + break; + + size_t heap_objs_found = 0; + HEAPENTRY32 heap_entry; + heap_entry.dwSize = sizeof(HEAPENTRY32); + if(Heap32First(&heap_entry, heap_list.th32ProcessID, + heap_list.th32HeapID)) + { + do + { + if(heap_objs_found++ > HEAP_OBJS_PER_LIST) + break; + accum.add(heap_entry, 1); + } while(Heap32Next(&heap_entry)); + } + + if(accum.polling_goal_achieved()) + break; + + } while(Heap32ListNext(snapshot, &heap_list)); + } + } + + CloseHandle(snapshot); + } + +} +#endif + +/* +* Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher) : + buffer(DEFAULT_BUFFERSIZE) + { + cipher = stream_cipher; + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher, + const SymmetricKey& key) : + buffer(DEFAULT_BUFFERSIZE) + { + cipher = stream_cipher; + cipher->set_key(key); + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + cipher = af.make_stream_cipher(sc_name); + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, + const SymmetricKey& key) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + cipher = af.make_stream_cipher(sc_name); + cipher->set_key(key); + } + +/* +* Set the IV of a stream cipher +*/ +void StreamCipher_Filter::set_iv(const InitializationVector& iv) + { + cipher->set_iv(iv.begin(), iv.length()); + } + +/* +* Write data into a StreamCipher_Filter +*/ +void StreamCipher_Filter::write(const byte input[], size_t length) + { + while(length) + { + size_t copied = std::min(length, buffer.size()); + cipher->cipher(input, &buffer[0], copied); + send(buffer, copied); + input += copied; + length -= copied; + } + } + +/* +* Hash_Filter Constructor +*/ +Hash_Filter::Hash_Filter(const std::string& algo_spec, + size_t len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + hash = af.make_hash_function(algo_spec); + } + +/* +* Complete a calculation by a Hash_Filter +*/ +void Hash_Filter::end_msg() + { + SecureVector output = hash->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + mac = af.make_mac(mac_name); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, + size_t len) : OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + mac = af.make_mac(mac_name); + mac->set_key(key); + } + +/* +* Complete a calculation by a MAC_Filter +*/ +void MAC_Filter::end_msg() + { + SecureVector output = mac->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +} +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +void Keyed_Filter::set_iv(const InitializationVector& iv) + { + if(iv.length() != 0) + throw Invalid_IV_Length(name(), iv.length()); + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* filters[], size_t count) + { + for(size_t j = 0; j != count; ++j) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +std::string Chain::name() const + { + return "Chain"; + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* filters[], size_t count) + { + set_next(filters, count); + } + +std::string Fork::name() const + { + return "Fork"; + } + +} +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Buffered_Filter Constructor +*/ +Buffered_Filter::Buffered_Filter(size_t b, size_t f) : + main_block_mod(b), final_minimum(f) + { + if(main_block_mod == 0) + throw std::invalid_argument("main_block_mod == 0"); + + if(final_minimum > main_block_mod) + throw std::invalid_argument("final_minimum > main_block_mod"); + + buffer.resize(2 * main_block_mod); + buffer_pos = 0; + } + +/* +* Buffer input into blocks, trying to minimize copying +*/ +void Buffered_Filter::write(const byte input[], size_t input_size) + { + if(!input_size) + return; + + if(buffer_pos + input_size >= main_block_mod + final_minimum) + { + size_t to_copy = std::min(buffer.size() - buffer_pos, input_size); + + copy_mem(&buffer[buffer_pos], input, to_copy); + buffer_pos += to_copy; + + input += to_copy; + input_size -= to_copy; + + size_t total_to_consume = + round_down(std::min(buffer_pos, + buffer_pos + input_size - final_minimum), + main_block_mod); + + buffered_block(&buffer[0], total_to_consume); + + buffer_pos -= total_to_consume; + + copy_mem(&buffer[0], &buffer[total_to_consume], buffer_pos); + } + + if(input_size >= final_minimum) + { + size_t full_blocks = (input_size - final_minimum) / main_block_mod; + size_t to_copy = full_blocks * main_block_mod; + + if(to_copy) + { + buffered_block(input, to_copy); + + input += to_copy; + input_size -= to_copy; + } + } + + copy_mem(&buffer[buffer_pos], input, input_size); + buffer_pos += input_size; + } + +/* +* Finish/flush operation +*/ +void Buffered_Filter::end_msg() + { + if(buffer_pos < final_minimum) + throw std::runtime_error("Buffered filter end_msg without enough input"); + + size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod; + + if(spare_blocks) + { + size_t spare_bytes = main_block_mod * spare_blocks; + buffered_block(&buffer[0], spare_bytes); + buffered_final(&buffer[spare_bytes], buffer_pos - spare_bytes); + } + else + { + buffered_final(&buffer[0], buffer_pos); + } + + buffer_pos = 0; + } + +} +/* +* Base64 Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Base64_Encoder Constructor +*/ +Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) : + line_length(breaks ? length : 0), + trailing_newline(t_n && breaks), + in(48), + out(64), + position(0), + out_position(0) + { + } + +/* +* Encode and send a block +*/ +void Base64_Encoder::encode_and_send(const byte input[], size_t length, + bool final_inputs) + { + while(length) + { + const size_t proc = std::min(length, in.size()); + + size_t consumed = 0; + size_t produced = base64_encode(reinterpret_cast(&out[0]), input, + proc, consumed, final_inputs); + + do_output(&out[0], produced); + + // FIXME: s/proc/consumed/? + input += proc; + length -= proc; + } + } + +/* +* Handle the output +*/ +void Base64_Encoder::do_output(const byte input[], size_t length) + { + if(line_length == 0) + send(input, length); + else + { + size_t remaining = length, offset = 0; + while(remaining) + { + size_t sent = std::min(line_length - out_position, remaining); + send(input + offset, sent); + out_position += sent; + remaining -= sent; + offset += sent; + if(out_position == line_length) + { + send('\n'); + out_position = 0; + } + } + } + } + +/* +* Convert some data into Base64 +*/ +void Base64_Encoder::write(const byte input[], size_t length) + { + in.copy(position, input, length); + if(position + length >= in.size()) + { + encode_and_send(&in[0], in.size()); + input += (in.size() - position); + length -= (in.size() - position); + while(length >= in.size()) + { + encode_and_send(input, in.size()); + input += in.size(); + length -= in.size(); + } + in.copy(input, length); + position = 0; + } + position += length; + } + +/* +* Flush buffers +*/ +void Base64_Encoder::end_msg() + { + encode_and_send(&in[0], position, true); + + if(trailing_newline || (out_position && line_length)) + send('\n'); + + out_position = position = 0; + } + +/* +* Base64_Decoder Constructor +*/ +Base64_Decoder::Base64_Decoder(Decoder_Checking c) : + checking(c), in(64), out(48), position(0) + { + } + +/* +* Convert some data from Base64 +*/ +void Base64_Decoder::write(const byte input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + false, + checking != FULL_CHECK); + + send(out, written); + + if(consumed != position) + { + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; + } + else + position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Base64_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + true, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; + + position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Base64_Decoder: Input not full bytes"); + } + +} +/* +* Hex Encoder/Decoder +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* Size used for internal buffer in hex encoder/decoder +*/ +const size_t HEX_CODEC_BUFFER_SIZE = 256; + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) : + casing(c), line_length(breaks ? length : 0) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(2*in.size()); + counter = position = 0; + } + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(2*in.size()); + counter = position = 0; + } + +/* +* Encode and send a block +*/ +void Hex_Encoder::encode_and_send(const byte block[], size_t length) + { + hex_encode(reinterpret_cast(&out[0]), + block, length, + casing == Uppercase); + + if(line_length == 0) + send(out, 2*length); + else + { + size_t remaining = 2*length, offset = 0; + while(remaining) + { + size_t sent = std::min(line_length - counter, remaining); + send(&out[offset], sent); + counter += sent; + remaining -= sent; + offset += sent; + if(counter == line_length) + { + send('\n'); + counter = 0; + } + } + } + } + +/* +* Convert some data into hex format +*/ +void Hex_Encoder::write(const byte input[], size_t length) + { + in.copy(position, input, length); + if(position + length >= in.size()) + { + encode_and_send(&in[0], in.size()); + input += (in.size() - position); + length -= (in.size() - position); + while(length >= in.size()) + { + encode_and_send(input, in.size()); + input += in.size(); + length -= in.size(); + } + in.copy(input, length); + position = 0; + } + position += length; + } + +/* +* Flush buffers +*/ +void Hex_Encoder::end_msg() + { + encode_and_send(&in[0], position); + if(counter && line_length) + send('\n'); + counter = position = 0; + } + +/* +* Hex_Decoder Constructor +*/ +Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c) + { + in.resize(HEX_CODEC_BUFFER_SIZE); + out.resize(in.size() / 2); + position = 0; + } + +/* +* Convert some data from hex format +*/ +void Hex_Decoder::write(const byte input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + size_t consumed = 0; + size_t written = hex_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + if(consumed != position) + { + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; + } + else + position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Hex_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = hex_decode(&out[0], + reinterpret_cast(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; + + position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Hex_Decoder: Input not full bytes"); + } + +} +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Write to a stream +*/ +void DataSink_Stream::write(const byte out[], size_t length) + { + sink.write(reinterpret_cast(out), length); + if(!sink.good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + + identifier); + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(std::ostream& out, + const std::string& name) : + identifier(name), + sink_p(0), + sink(out) + { + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(const std::string& path, + bool use_binary) : + identifier(path), + sink_p(new std::ofstream( + path.c_str(), + use_binary ? std::ios::binary : std::ios::out)), + sink(*sink_p) + { + if(!sink.good()) + { + delete sink_p; + throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); + } + } + +/* +* DataSink_Stream Destructor +*/ +DataSink_Stream::~DataSink_Stream() + { + delete sink_p; + } + +} +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Read a single byte from the DataSource +*/ +size_t DataSource::read_byte(byte& out) + { + return read(&out, 1); + } + +/* +* Peek a single byte from the DataSource +*/ +size_t DataSource::peek_byte(byte& out) const + { + return peek(&out, 1, 0); + } + +/* +* Discard the next N bytes of the data +*/ +size_t DataSource::discard_next(size_t n) + { + size_t discarded = 0; + byte dummy; + for(size_t j = 0; j != n; ++j) + discarded += read_byte(dummy); + return discarded; + } + +/* +* Read from a memory buffer +*/ +size_t DataSource_Memory::read(byte out[], size_t length) + { + size_t got = std::min(source.size() - offset, length); + copy_mem(out, &source[offset], got); + offset += got; + return got; + } + +/* +* Peek into a memory buffer +*/ +size_t DataSource_Memory::peek(byte out[], size_t length, + size_t peek_offset) const + { + const size_t bytes_left = source.size() - offset; + if(peek_offset >= bytes_left) return 0; + + size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, &source[offset + peek_offset], got); + return got; + } + +/* +* Check if the memory buffer is empty +*/ +bool DataSource_Memory::end_of_data() const + { + return (offset == source.size()); + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const byte in[], size_t length) : + source(in, length) + { + offset = 0; + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const MemoryRegion& in) : + source(in) + { + offset = 0; + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const std::string& in) : + source(reinterpret_cast(in.data()), in.length()) + { + offset = 0; + } + +/* +* Read from a stream +*/ +size_t DataSource_Stream::read(byte out[], size_t length) + { + source.read(reinterpret_cast(out), length); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + size_t got = source.gcount(); + total_read += got; + return got; + } + +/* +* Peek into a stream +*/ +size_t DataSource_Stream::peek(byte out[], size_t length, size_t offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + size_t got = 0; + + if(offset) + { + SecureVector buf(offset); + source.read(reinterpret_cast(&buf[0]), buf.size()); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source.gcount(); + } + + if(got == offset) + { + source.read(reinterpret_cast(out), length); + if(source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source.gcount(); + } + + if(source.eof()) + source.clear(); + source.seekg(total_read, std::ios::beg); + + return got; + } + +/* +* Check if the stream is empty or in error +*/ +bool DataSource_Stream::end_of_data() const + { + return (!source.good()); + } + +/* +* Return a human-readable ID for this stream +*/ +std::string DataSource_Stream::id() const + { + return identifier; + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(const std::string& path, + bool use_binary) : + identifier(path), + source_p(new std::ifstream( + path.c_str(), + use_binary ? std::ios::binary : std::ios::in)), + source(*source_p), + total_read(0) + { + if(!source.good()) + { + delete source_p; + throw Stream_IO_Error("DataSource: Failure opening file " + path); + } + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(std::istream& in, + const std::string& name) : + identifier(name), + source_p(0), + source(in), + total_read(0) + { + } + +/* +* DataSource_Stream Destructor +*/ +DataSource_Stream::~DataSource_Stream() + { + delete source_p; + } + +} + +#ifdef Q_OS_UNIX +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Write data from a pipe into a Unix fd +*/ +int operator<<(int fd, Pipe& pipe) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + size_t position = 0; + while(got) + { + ssize_t ret = write(fd, &buffer[position], got); + if(ret == -1) + throw Stream_IO_Error("Pipe output operator (unixfd) has failed"); + position += ret; + got -= ret; + } + } + return fd; + } + +/* +* Read data from a Unix fd into a pipe +*/ +int operator>>(int fd, Pipe& pipe) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(true) + { + ssize_t ret = read(fd, &buffer[0], buffer.size()); + if(ret == 0) break; + if(ret == -1) + throw Stream_IO_Error("Pipe input operator (unixfd) has failed"); + pipe.write(&buffer[0], ret); + } + return fd; + } + +} +#endif + +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Filter Constructor +*/ +Filter::Filter() + { + next.resize(1); + port_num = 0; + filter_owns = 0; + owned = false; + } + +/* +* Send data to all ports +*/ +void Filter::send(const byte input[], size_t length) + { + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + { + if(write_queue.size()) + next[j]->write(&write_queue[0], write_queue.size()); + next[j]->write(input, length); + nothing_attached = false; + } + + if(nothing_attached) + write_queue += std::make_pair(input, length); + else + write_queue.clear(); + } + +/* +* Start a new message +*/ +void Filter::new_msg() + { + start_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->new_msg(); + } + +/* +* End the current message +*/ +void Filter::finish_msg() + { + end_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->finish_msg(); + } + +/* +* Attach a filter to the current port +*/ +void Filter::attach(Filter* new_filter) + { + if(new_filter) + { + Filter* last = this; + while(last->get_next()) + last = last->get_next(); + last->next[last->current_port()] = new_filter; + } + } + +/* +* Set the active port on a filter +*/ +void Filter::set_port(size_t new_port) + { + if(new_port >= total_ports()) + throw Invalid_Argument("Filter: Invalid port number"); + port_num = new_port; + } + +/* +* Return the next Filter in the logical chain +*/ +Filter* Filter::get_next() const + { + if(port_num < next.size()) + return next[port_num]; + return 0; + } + +/* +* Set the next Filters +*/ +void Filter::set_next(Filter* filters[], size_t size) + { + while(size && filters && filters[size-1] == 0) + --size; + + next.clear(); + next.resize(size); + + port_num = 0; + filter_owns = 0; + + for(size_t j = 0; j != size; ++j) + next[j] = filters[j]; + } + +/* +* Return the total number of ports +*/ +size_t Filter::total_ports() const + { + return next.size(); + } + +} +/* +* CBC Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* CBC Encryption Constructor +*/ +CBC_Encryption::CBC_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + Buffered_Filter(ciph->block_size(), 0), + cipher(ciph), padder(pad) + { + if(!padder->valid_blocksize(cipher->block_size())) + throw Invalid_Block_Size(name(), padder->name()); + + state.resize(cipher->block_size()); + } + +/* +* CBC Encryption Constructor +*/ +CBC_Encryption::CBC_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key, + const InitializationVector& iv) : + Buffered_Filter(ciph->block_size(), 0), + cipher(ciph), padder(pad) + { + if(!padder->valid_blocksize(cipher->block_size())) + throw Invalid_Block_Size(name(), padder->name()); + + state.resize(cipher->block_size()); + + set_key(key); + set_iv(iv); + } + +/* +* Set the IV +*/ +void CBC_Encryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + buffer_reset(); + } + +/* +* Encrypt in CBC mode +*/ +void CBC_Encryption::buffered_block(const byte input[], size_t length) + { + size_t blocks = length / state.size(); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(state, input + i * cipher->block_size(), state.size()); + cipher->encrypt(state); + send(state, state.size()); + } + } + +/* +* Finish encrypting in CBC mode +*/ +void CBC_Encryption::buffered_final(const byte input[], size_t length) + { + if(length % cipher->block_size() == 0) + buffered_block(input, length); + else if(length != 0) + throw Encoding_Error(name() + ": Did not pad to full blocksize"); + } + +void CBC_Encryption::write(const byte input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void CBC_Encryption::end_msg() + { + size_t last_block = current_position() % cipher->block_size(); + + SecureVector padding(cipher->block_size()); + padder->pad(padding, padding.size(), last_block); + + size_t pad_bytes = padder->pad_bytes(cipher->block_size(), last_block); + + if(pad_bytes) + Buffered_Filter::write(padding, pad_bytes); + Buffered_Filter::end_msg(); + } + +/* +* Return a CBC mode name +*/ +std::string CBC_Encryption::name() const + { + return (cipher->name() + "/CBC/" + padder->name()); + } + +/* +* CBC Decryption Constructor +*/ +CBC_Decryption::CBC_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + Buffered_Filter(ciph->parallel_bytes(), ciph->block_size()), + cipher(ciph), padder(pad) + { + if(!padder->valid_blocksize(cipher->block_size())) + throw Invalid_Block_Size(name(), padder->name()); + + state.resize(cipher->block_size()); + temp.resize(buffered_block_size()); + } + +/* +* CBC Decryption Constructor +*/ +CBC_Decryption::CBC_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key, + const InitializationVector& iv) : + Buffered_Filter(ciph->parallel_bytes(), ciph->block_size()), + cipher(ciph), padder(pad) + { + if(!padder->valid_blocksize(cipher->block_size())) + throw Invalid_Block_Size(name(), padder->name()); + + state.resize(cipher->block_size()); + temp.resize(buffered_block_size()); + + set_key(key); + set_iv(iv); + } + +/* +* Set the IV +*/ +void CBC_Decryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + buffer_reset(); + } + +/* +* Decrypt in CBC mode +*/ +void CBC_Decryption::buffered_block(const byte input[], size_t length) + { + const size_t blocks_in_temp = temp.size() / cipher->block_size(); + size_t blocks = length / cipher->block_size(); + + while(blocks) + { + size_t to_proc = std::min(blocks, blocks_in_temp); + + cipher->decrypt_n(input, &temp[0], to_proc); + + xor_buf(temp, state, cipher->block_size()); + + for(size_t i = 1; i < to_proc; ++i) + xor_buf(&temp[i * cipher->block_size()], + input + (i-1) * cipher->block_size(), + cipher->block_size()); + + copy_mem(&state[0], + input + (to_proc - 1) * cipher->block_size(), + cipher->block_size()); + + send(temp, to_proc * cipher->block_size()); + + input += to_proc * cipher->block_size(); + blocks -= to_proc; + } + } + +/* +* Finish encrypting in CBC mode +*/ +void CBC_Decryption::buffered_final(const byte input[], size_t length) + { + if(length == 0 || length % cipher->block_size() != 0) + throw Decoding_Error(name() + ": Ciphertext not multiple of block size"); + + size_t extra_blocks = (length - 1) / cipher->block_size(); + + buffered_block(input, extra_blocks * cipher->block_size()); + + input += extra_blocks * cipher->block_size(); + + cipher->decrypt(input, temp); + xor_buf(temp, state, cipher->block_size()); + send(temp, padder->unpad(temp, cipher->block_size())); + + copy_mem(&state[0], input, state.size()); // save for IV chaining + } + +/* +* Decrypt in CBC mode +*/ +void CBC_Decryption::write(const byte input[], size_t length) + { + Buffered_Filter::write(input, length); + } + +/* +* Finish decrypting in CBC mode +*/ +void CBC_Decryption::end_msg() + { + Buffered_Filter::end_msg(); + } + +/* +* Return a CBC mode name +*/ +std::string CBC_Decryption::name() const + { + return (cipher->name() + "/CBC/" + padder->name()); + } + +} +/* +* CFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* CFB Encryption Constructor +*/ +CFB_Encryption::CFB_Encryption(BlockCipher* ciph, size_t fback_bits) + { + cipher = ciph; + feedback = fback_bits ? fback_bits / 8: cipher->block_size(); + + buffer.resize(cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + + if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size()) + throw Invalid_Argument("CFB_Encryption: Invalid feedback size " + + to_string(fback_bits)); + } + +/* +* CFB Encryption Constructor +*/ +CFB_Encryption::CFB_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + size_t fback_bits) + { + cipher = ciph; + feedback = fback_bits ? fback_bits / 8: cipher->block_size(); + + buffer.resize(cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + + if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size()) + throw Invalid_Argument("CFB_Encryption: Invalid feedback size " + + to_string(fback_bits)); + + set_key(key); + set_iv(iv); + } + +void CFB_Encryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + zeroise(buffer); + position = 0; + + cipher->encrypt(state, buffer); + } + +/* +* Encrypt data in CFB mode +*/ +void CFB_Encryption::write(const byte input[], size_t length) + { + while(length) + { + size_t xored = std::min(feedback - position, length); + xor_buf(&buffer[position], input, xored); + send(&buffer[position], xored); + input += xored; + length -= xored; + position += xored; + + if(position == feedback) + { + for(size_t j = 0; j != cipher->block_size() - feedback; ++j) + state[j] = state[j + feedback]; + state.copy(cipher->block_size() - feedback, buffer, feedback); + cipher->encrypt(state, buffer); + position = 0; + } + } + } + +/* +* CFB Decryption Constructor +*/ +CFB_Decryption::CFB_Decryption(BlockCipher* ciph, size_t fback_bits) + { + cipher = ciph; + feedback = fback_bits ? fback_bits / 8: cipher->block_size(); + + buffer.resize(cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + + if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size()) + throw Invalid_Argument("CFB_Decryption: Invalid feedback size " + + to_string(fback_bits)); + } + +/* +* CFB Decryption Constructor +*/ +CFB_Decryption::CFB_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + size_t fback_bits) + { + cipher = ciph; + feedback = fback_bits ? fback_bits / 8: cipher->block_size(); + + buffer.resize(cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + + if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size()) + throw Invalid_Argument("CFB_Decryption: Invalid feedback size " + + to_string(fback_bits)); + + set_key(key); + set_iv(iv); + } + +void CFB_Decryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + zeroise(buffer); + position = 0; + + cipher->encrypt(state, buffer); + } + +/* +* Decrypt data in CFB mode +*/ +void CFB_Decryption::write(const byte input[], size_t length) + { + while(length) + { + size_t xored = std::min(feedback - position, length); + xor_buf(&buffer[position], input, xored); + send(&buffer[position], xored); + buffer.copy(position, input, xored); + input += xored; + length -= xored; + position += xored; + if(position == feedback) + { + for(size_t j = 0; j != cipher->block_size() - feedback; ++j) + state[j] = state[j + feedback]; + state.copy(cipher->block_size() - feedback, buffer, feedback); + cipher->encrypt(state, buffer); + position = 0; + } + } + } + +} +/* +* CTS Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* CTS Encryption Constructor +*/ +CTS_Encryption::CTS_Encryption(BlockCipher* ciph) : + cipher(ciph) + { + buffer.resize(2 * cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + } + +/* +* CTS Encryption Constructor +*/ +CTS_Encryption::CTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + cipher(ciph) + { + buffer.resize(2 * cipher->block_size()); + state.resize(cipher->block_size()); + position = 0; + + set_key(key); + set_iv(iv); + } + +/* +* Set the IV +*/ +void CTS_Encryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + zeroise(buffer); + position = 0; + } + +/* +* Encrypt a block +*/ +void CTS_Encryption::encrypt(const byte block[]) + { + xor_buf(state, block, cipher->block_size()); + cipher->encrypt(state); + send(state, cipher->block_size()); + } + +/* +* Encrypt in CTS mode +*/ +void CTS_Encryption::write(const byte input[], size_t length) + { + size_t copied = std::min(buffer.size() - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + encrypt(&buffer[0]); + if(length > cipher->block_size()) + { + encrypt(&buffer[cipher->block_size()]); + while(length > 2*cipher->block_size()) + { + encrypt(input); + length -= cipher->block_size(); + input += cipher->block_size(); + } + position = 0; + } + else + { + copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size()); + position = cipher->block_size(); + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish encrypting in CTS mode +*/ +void CTS_Encryption::end_msg() + { + if(position < cipher->block_size() + 1) + throw Encoding_Error(name() + ": insufficient data to encrypt"); + + xor_buf(state, buffer, cipher->block_size()); + cipher->encrypt(state); + SecureVector cn = state; + clear_mem(&buffer[position], buffer.size() - position); + encrypt(&buffer[cipher->block_size()]); + send(cn, position - cipher->block_size()); + } + +/* +* CTS Decryption Constructor +*/ +CTS_Decryption::CTS_Decryption(BlockCipher* ciph) : + cipher(ciph) + { + buffer.resize(2 * cipher->block_size()); + state.resize(cipher->block_size()); + temp.resize(cipher->block_size()); + position = 0; + } + +/* +* CTS Decryption Constructor +*/ +CTS_Decryption::CTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + cipher(ciph) + { + buffer.resize(2 * cipher->block_size()); + state.resize(cipher->block_size()); + temp.resize(cipher->block_size()); + position = 0; + + set_key(key); + set_iv(iv); + } + +/* +* Set the IV +*/ +void CTS_Decryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + state = iv.bits_of(); + zeroise(buffer); + position = 0; + } + +/* +* Decrypt a block +*/ +void CTS_Decryption::decrypt(const byte block[]) + { + cipher->decrypt(block, &temp[0]); + xor_buf(temp, state, cipher->block_size()); + send(temp, cipher->block_size()); + state.copy(block, cipher->block_size()); + } + +/* +* Decrypt in CTS mode +*/ +void CTS_Decryption::write(const byte input[], size_t length) + { + size_t copied = std::min(buffer.size() - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + decrypt(buffer); + if(length > cipher->block_size()) + { + decrypt(&buffer[cipher->block_size()]); + while(length > 2*cipher->block_size()) + { + decrypt(input); + length -= cipher->block_size(); + input += cipher->block_size(); + } + position = 0; + } + else + { + copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size()); + position = cipher->block_size(); + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish decrypting in CTS mode +*/ +void CTS_Decryption::end_msg() + { + cipher->decrypt(buffer, temp); + xor_buf(temp, &buffer[cipher->block_size()], position - cipher->block_size()); + + SecureVector xn = temp; + + copy_mem(&buffer[position], + &xn[position - cipher->block_size()], + buffer.size() - position); + + cipher->decrypt(&buffer[cipher->block_size()], temp); + xor_buf(temp, state, cipher->block_size()); + send(temp, cipher->block_size()); + send(xn, position - cipher->block_size()); + } + +} +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* EAX MAC-based PRF +*/ +SecureVector eax_prf(byte tag, size_t BLOCK_SIZE, + MessageAuthenticationCode* mac, + const byte in[], size_t length) + { + for(size_t i = 0; i != BLOCK_SIZE - 1; ++i) + mac->update(0); + mac->update(tag); + mac->update(in, length); + return mac->final(); + } + +} + +/* +* EAX_Base Constructor +*/ +EAX_Base::EAX_Base(BlockCipher* cipher, size_t tag_size) : + BLOCK_SIZE(cipher->block_size()), + TAG_SIZE(tag_size ? tag_size / 8 : BLOCK_SIZE), + cipher_name(cipher->name()), + ctr_buf(DEFAULT_BUFFERSIZE) + { + cmac = new CMAC(cipher->clone()); + ctr = new CTR_BE(cipher); // takes ownership + + if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > cmac->output_length()) + throw Invalid_Argument(name() + ": Bad tag size " + to_string(tag_size)); + } + +/* +* Check if a keylength is valid for EAX +*/ +bool EAX_Base::valid_keylength(size_t n) const + { + if(!ctr->valid_keylength(n)) + return false; + return true; + } + +/* +* Set the EAX key +*/ +void EAX_Base::set_key(const SymmetricKey& key) + { + /* + * These could share the key schedule, which is one nice part of EAX, + * but it's much easier to ignore that here... + */ + ctr->set_key(key); + cmac->set_key(key); + + header_mac = eax_prf(1, BLOCK_SIZE, cmac, 0, 0); + } + +/* +* Do setup at the start of each message +*/ +void EAX_Base::start_msg() + { + for(size_t i = 0; i != BLOCK_SIZE - 1; ++i) + cmac->update(0); + cmac->update(2); + } + +/* +* Set the EAX nonce +*/ +void EAX_Base::set_iv(const InitializationVector& iv) + { + nonce_mac = eax_prf(0, BLOCK_SIZE, cmac, iv.begin(), iv.length()); + ctr->set_iv(&nonce_mac[0], nonce_mac.size()); + } + +/* +* Set the EAX header +*/ +void EAX_Base::set_header(const byte header[], size_t length) + { + header_mac = eax_prf(1, BLOCK_SIZE, cmac, header, length); + } + +/* +* Return the name of this cipher mode +*/ +std::string EAX_Base::name() const + { + return (cipher_name + "/EAX"); + } + +/* +* Encrypt in EAX mode +*/ +void EAX_Encryption::write(const byte input[], size_t length) + { + while(length) + { + size_t copied = std::min(length, ctr_buf.size()); + + ctr->cipher(input, &ctr_buf[0], copied); + cmac->update(&ctr_buf[0], copied); + + send(ctr_buf, copied); + input += copied; + length -= copied; + } + } + +/* +* Finish encrypting in EAX mode +*/ +void EAX_Encryption::end_msg() + { + SecureVector data_mac = cmac->final(); + xor_buf(data_mac, nonce_mac, data_mac.size()); + xor_buf(data_mac, header_mac, data_mac.size()); + + send(data_mac, TAG_SIZE); + } + +} +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* EAX_Decryption Constructor +*/ +EAX_Decryption::EAX_Decryption(BlockCipher* ciph, + size_t tag_size) : + EAX_Base(ciph, tag_size) + { + queue.resize(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/* +* EAX_Decryption Constructor +*/ +EAX_Decryption::EAX_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + size_t tag_size) : + EAX_Base(ciph, tag_size) + { + set_key(key); + set_iv(iv); + queue.resize(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/* +* Decrypt in EAX mode +*/ +void EAX_Decryption::write(const byte input[], size_t length) + { + while(length) + { + const size_t copied = std::min(length, queue.size() - queue_end); + + queue.copy(queue_end, input, copied); + input += copied; + length -= copied; + queue_end += copied; + + while((queue_end - queue_start) > TAG_SIZE) + { + size_t removed = (queue_end - queue_start) - TAG_SIZE; + do_write(&queue[queue_start], removed); + queue_start += removed; + } + + if(queue_start + TAG_SIZE == queue_end && + queue_start >= queue.size() / 2) + { + SecureVector queue_data(TAG_SIZE); + queue_data.copy(&queue[queue_start], TAG_SIZE); + queue.copy(&queue_data[0], TAG_SIZE); + queue_start = 0; + queue_end = TAG_SIZE; + } + } + } + +/* +* Decrypt in EAX mode +*/ +void EAX_Decryption::do_write(const byte input[], size_t length) + { + while(length) + { + size_t copied = std::min(length, ctr_buf.size()); + + /* + Process same block with cmac and ctr at the same time to + help cache locality. + */ + cmac->update(input, copied); + ctr->cipher(input, &ctr_buf[0], copied); + send(ctr_buf, copied); + input += copied; + length -= copied; + } + } + +/* +* Finish decrypting in EAX mode +*/ +void EAX_Decryption::end_msg() + { + if((queue_end - queue_start) != TAG_SIZE) + throw Decoding_Error(name() + ": Message authentication failure"); + + SecureVector data_mac = cmac->final(); + + for(size_t j = 0; j != TAG_SIZE; ++j) + if(queue[queue_start+j] != (data_mac[j] ^ nonce_mac[j] ^ header_mac[j])) + throw Decoding_Error(name() + ": Message authentication failure"); + + queue_start = queue_end = 0; + } + +} +/* +* ECB Mode +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* ECB_Encryption Constructor +*/ +ECB_Encryption::ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + Buffered_Filter(ciph->parallel_bytes(), 0) + { + cipher = ciph; + padder = pad; + + temp.resize(buffered_block_size()); + } + +/* +* ECB_Encryption Constructor +*/ +ECB_Encryption::ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key) : + Buffered_Filter(ciph->parallel_bytes(), 0) + { + cipher = ciph; + padder = pad; + + temp.resize(buffered_block_size()); + + cipher->set_key(key); + } + +/* +* ECB_Encryption Destructor +*/ +ECB_Encryption::~ECB_Encryption() + { + delete cipher; + delete padder; + } + +/* +* Return an ECB mode name +*/ +std::string ECB_Encryption::name() const + { + return (cipher->name() + "/ECB/" + padder->name()); + } + +/* +* Encrypt in ECB mode +*/ +void ECB_Encryption::write(const byte input[], size_t length) + { + Buffered_Filter::write(input, length); + } + +/* +* Finish encrypting in ECB mode +*/ +void ECB_Encryption::end_msg() + { + size_t last_block = current_position() % cipher->block_size(); + + SecureVector padding(cipher->block_size()); + padder->pad(padding, padding.size(), last_block); + + size_t pad_bytes = padder->pad_bytes(cipher->block_size(), last_block); + + if(pad_bytes) + Buffered_Filter::write(padding, pad_bytes); + Buffered_Filter::end_msg(); + } + +void ECB_Encryption::buffered_block(const byte input[], size_t input_length) + { + const size_t blocks_in_temp = temp.size() / cipher->block_size(); + size_t blocks = input_length / cipher->block_size(); + + while(blocks) + { + size_t to_proc = std::min(blocks, blocks_in_temp); + + cipher->encrypt_n(input, &temp[0], to_proc); + + send(temp, to_proc * cipher->block_size()); + + input += to_proc * cipher->block_size(); + blocks -= to_proc; + } + } + +void ECB_Encryption::buffered_final(const byte input[], size_t input_length) + { + if(input_length % cipher->block_size() == 0) + buffered_block(input, input_length); + else if(input_length != 0) + throw Encoding_Error(name() + ": Did not pad to full blocksize"); + } + +/* +* ECB_Decryption Constructor +*/ +ECB_Decryption::ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + Buffered_Filter(ciph->parallel_bytes(), 1) + { + cipher = ciph; + padder = pad; + + temp.resize(buffered_block_size()); + } + +/* +* ECB_Decryption Constructor +*/ +ECB_Decryption::ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key) : + Buffered_Filter(ciph->parallel_bytes(), 1) + { + cipher = ciph; + padder = pad; + + temp.resize(buffered_block_size()); + + cipher->set_key(key); + } + +/* +* ECB_Decryption Destructor +*/ +ECB_Decryption::~ECB_Decryption() + { + delete cipher; + delete padder; + } + +/* +* Return an ECB mode name +*/ +std::string ECB_Decryption::name() const + { + return (cipher->name() + "/ECB/" + padder->name()); + } + +/* +* Decrypt in ECB mode +*/ +void ECB_Decryption::write(const byte input[], size_t length) + { + Buffered_Filter::write(input, length); + } + +/* +* Finish decrypting in ECB mode +*/ +void ECB_Decryption::end_msg() + { + Buffered_Filter::end_msg(); + } + +/* +* Decrypt in ECB mode +*/ +void ECB_Decryption::buffered_block(const byte input[], size_t length) + { + const size_t blocks_in_temp = temp.size() / cipher->block_size(); + size_t blocks = length / cipher->block_size(); + + while(blocks) + { + size_t to_proc = std::min(blocks, blocks_in_temp); + + cipher->decrypt_n(input, &temp[0], to_proc); + + send(temp, to_proc * cipher->block_size()); + + input += to_proc * cipher->block_size(); + blocks -= to_proc; + } + } + +/* +* Finish encrypting in ECB mode +*/ +void ECB_Decryption::buffered_final(const byte input[], size_t length) + { + if(length == 0 || length % cipher->block_size() != 0) + throw Decoding_Error(name() + ": Ciphertext not multiple of block size"); + + size_t extra_blocks = (length - 1) / cipher->block_size(); + + buffered_block(input, extra_blocks * cipher->block_size()); + + input += extra_blocks * cipher->block_size(); + + cipher->decrypt(input, temp); + send(temp, padder->unpad(temp, cipher->block_size())); + } + +} +/* +* CBC Padding Methods +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Default amount of padding +*/ +size_t BlockCipherModePaddingMethod::pad_bytes(size_t bs, size_t pos) const + { + return (bs - pos); + } + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::pad(byte block[], size_t size, size_t position) const + { + const size_t bytes_remaining = size - position; + const byte pad_value = static_cast(bytes_remaining); + + BOTAN_ASSERT_EQUAL(pad_value, bytes_remaining, + "Overflow in PKCS7_Padding"); + + for(size_t j = 0; j != size; ++j) + block[j] = pad_value; + } + +/* +* Unpad with PKCS #7 Method +*/ +size_t PKCS7_Padding::unpad(const byte block[], size_t size) const + { + size_t position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(size_t j = size-position; j != size-1; ++j) + if(block[j] != position) + throw Decoding_Error(name()); + return (size-position); + } + +/* +* Query if the size is valid for this method +*/ +bool PKCS7_Padding::valid_blocksize(size_t size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::pad(byte block[], size_t size, size_t position) const + { + for(size_t j = 0; j != size-position; ++j) + block[j] = 0; + block[size-position-1] = static_cast(size-position); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +size_t ANSI_X923_Padding::unpad(const byte block[], size_t size) const + { + size_t position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(size_t j = size-position; j != size-1; ++j) + if(block[j] != 0) + throw Decoding_Error(name()); + return (size-position); + } + +/* +* Query if the size is valid for this method +*/ +bool ANSI_X923_Padding::valid_blocksize(size_t size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::pad(byte block[], size_t size, size_t) const + { + block[0] = 0x80; + for(size_t j = 1; j != size; ++j) + block[j] = 0x00; + } + +/* +* Unpad with One and Zeros Method +*/ +size_t OneAndZeros_Padding::unpad(const byte block[], size_t size) const + { + while(size) + { + if(block[size-1] == 0x80) + break; + if(block[size-1] != 0x00) + throw Decoding_Error(name()); + size--; + } + if(!size) + throw Decoding_Error(name()); + return (size-1); + } + +/* +* Query if the size is valid for this method +*/ +bool OneAndZeros_Padding::valid_blocksize(size_t size) const + { + return (size > 0); + } + +} +/* +* XTS Mode +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +void poly_double(byte tweak[], size_t size) + { + const byte polynomial = (size == 16) ? 0x87 : 0x1B; + + byte carry = 0; + for(size_t i = 0; i != size; ++i) + { + byte carry2 = (tweak[i] >> 7); + tweak[i] = (tweak[i] << 1) | carry; + carry = carry2; + } + + if(carry) + tweak[0] ^= polynomial; + } + +/* XTS needs to process at least 2 blocks in parallel + because block_size+1 bytes are needed at the end +*/ +size_t xts_parallelism(BlockCipher* cipher) + { + return std::max(cipher->parallel_bytes(), + 2 * cipher->block_size()); + } + +} + +/* +* XTS_Encryption constructor +*/ +XTS_Encryption::XTS_Encryption(BlockCipher* ciph) : + Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), + cipher(ciph) + { + if(cipher->block_size() != 8 && cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = cipher->clone(); + tweak.resize(buffered_block_size()); + } + +/* +* XTS_Encryption constructor +*/ +XTS_Encryption::XTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), + cipher(ciph) + { + if(cipher->block_size() != 8 && cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = cipher->clone(); + tweak.resize(buffered_block_size()); + + set_key(key); + set_iv(iv); + } + +/* +* Return the name +*/ +std::string XTS_Encryption::name() const + { + return (cipher->name() + "/XTS"); + } + +/* +* Set new tweak +*/ +void XTS_Encryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); + + tweak.copy(iv.begin(), iv.length()); + cipher2->encrypt(tweak); + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + tweak.copy(i*cipher->block_size(), + &tweak[(i-1)*cipher->block_size()], + cipher->block_size()); + + poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); + } + } + +void XTS_Encryption::set_key(const SymmetricKey& key) + { + size_t key_half = key.length() / 2; + + if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), key.length()); + + cipher->set_key(key.begin(), key_half); + cipher2->set_key(key.begin() + key_half, key_half); + } + +/* +* Encrypt in XTS mode +*/ +void XTS_Encryption::write(const byte input[], size_t length) + { + Buffered_Filter::write(input, length); + } +/* +* Finish encrypting in XTS mode +*/ +void XTS_Encryption::end_msg() + { + Buffered_Filter::end_msg(); + } + +void XTS_Encryption::buffered_block(const byte input[], size_t length) + { + const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); + size_t blocks = length / cipher->block_size(); + + SecureVector temp(tweak.size()); + + while(blocks) + { + size_t to_proc = std::min(blocks, blocks_in_tweak); + size_t to_proc_bytes = to_proc * cipher->block_size(); + + xor_buf(temp, input, tweak, to_proc_bytes); + + cipher->encrypt_n(&temp[0], &temp[0], to_proc); + + xor_buf(temp, tweak, to_proc_bytes); + + send(temp, to_proc_bytes); + + tweak.copy(&tweak[(to_proc-1)*cipher->block_size()], + cipher->block_size()); + poly_double(&tweak[0], cipher->block_size()); + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + tweak.copy(i*cipher->block_size(), + &tweak[(i-1)*cipher->block_size()], + cipher->block_size()); + + poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); + } + + input += to_proc * cipher->block_size(); + blocks -= to_proc; + } + } + +/* +* Finish encrypting in XTS mode +*/ +void XTS_Encryption::buffered_final(const byte input[], size_t length) + { + if(length <= cipher->block_size()) + throw Encoding_Error("XTS_Encryption: insufficient data to encrypt"); + + if(length % cipher->block_size() == 0) + { + buffered_block(input, length); + } + else + { // steal ciphertext + + size_t leftover_blocks = + ((length / cipher->block_size()) - 1) * cipher->block_size(); + + buffered_block(input, leftover_blocks); + + input += leftover_blocks; + length -= leftover_blocks; + + SecureVector temp(input, length); + + xor_buf(temp, tweak, cipher->block_size()); + cipher->encrypt(temp); + xor_buf(temp, tweak, cipher->block_size()); + + poly_double(&tweak[0], cipher->block_size()); + + for(size_t i = 0; i != length - cipher->block_size(); ++i) + std::swap(temp[i], temp[i + cipher->block_size()]); + + xor_buf(temp, tweak, cipher->block_size()); + cipher->encrypt(temp); + xor_buf(temp, tweak, cipher->block_size()); + + send(temp, temp.size()); + } + + buffer_reset(); + } + +/* +* XTS_Decryption constructor +*/ +XTS_Decryption::XTS_Decryption(BlockCipher* ciph) : + Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), + cipher(ciph) + { + if(cipher->block_size() != 8 && cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = ciph->clone(); + tweak.resize(buffered_block_size()); + } + +/* +* XTS_Decryption constructor +*/ +XTS_Decryption::XTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), + cipher(ciph) + { + if(cipher->block_size() != 8 && cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = ciph->clone(); + tweak.resize(buffered_block_size()); + + set_key(key); + set_iv(iv); + } + +/* +* Return the name +*/ +std::string XTS_Decryption::name() const + { + return (cipher->name() + "/XTS"); + } + +/* +* Set new tweak +*/ +void XTS_Decryption::set_iv(const InitializationVector& iv) + { + if(!valid_iv_length(iv.length())) + throw Invalid_IV_Length(name(), iv.length()); + + const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); + + tweak.copy(iv.begin(), iv.length()); + cipher2->encrypt(tweak); + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + tweak.copy(i*cipher->block_size(), + &tweak[(i-1)*cipher->block_size()], + cipher->block_size()); + + poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); + } + } + +void XTS_Decryption::set_key(const SymmetricKey& key) + { + size_t key_half = key.length() / 2; + + if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), key.length()); + + cipher->set_key(key.begin(), key_half); + cipher2->set_key(key.begin() + key_half, key_half); + } + +/* +* Decrypt in XTS mode +*/ +void XTS_Decryption::write(const byte input[], size_t length) + { + Buffered_Filter::write(input, length); + } + +/* +* Finish decrypting in XTS mode +*/ +void XTS_Decryption::end_msg() + { + Buffered_Filter::end_msg(); + } + +void XTS_Decryption::buffered_block(const byte input[], size_t input_length) + { + const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); + size_t blocks = input_length / cipher->block_size(); + + SecureVector temp(tweak.size()); + + while(blocks) + { + size_t to_proc = std::min(blocks, blocks_in_tweak); + size_t to_proc_bytes = to_proc * cipher->block_size(); + + xor_buf(temp, input, tweak, to_proc_bytes); + + cipher->decrypt_n(&temp[0], &temp[0], to_proc); + + xor_buf(temp, tweak, to_proc_bytes); + + send(temp, to_proc_bytes); + + tweak.copy(&tweak[(to_proc-1)*cipher->block_size()], + cipher->block_size()); + poly_double(&tweak[0], cipher->block_size()); + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + tweak.copy(i*cipher->block_size(), + &tweak[(i-1)*cipher->block_size()], + cipher->block_size()); + + poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); + } + + input += to_proc * cipher->block_size(); + blocks -= to_proc; + } + } + +void XTS_Decryption::buffered_final(const byte input[], size_t length) + { + if(length <= cipher->block_size()) + throw Decoding_Error("XTS_Decryption: insufficient data to decrypt"); + + if(length % cipher->block_size() == 0) + { + buffered_block(input, length); + } + else + { + size_t leftover_blocks = + ((length / cipher->block_size()) - 1) * cipher->block_size(); + + buffered_block(input, leftover_blocks); + + input += leftover_blocks; + length -= leftover_blocks; + + SecureVector temp(input, length); + SecureVector tweak_copy(&tweak[0], cipher->block_size()); + + poly_double(&tweak_copy[0], cipher->block_size()); + + xor_buf(temp, tweak_copy, cipher->block_size()); + cipher->decrypt(temp); + xor_buf(temp, tweak_copy, cipher->block_size()); + + for(size_t i = 0; i != length - cipher->block_size(); ++i) + std::swap(temp[i], temp[i + cipher->block_size()]); + + xor_buf(temp, tweak, cipher->block_size()); + cipher->decrypt(temp); + xor_buf(temp, tweak, cipher->block_size()); + + send(temp, length); + } + + buffer_reset(); + } + +} +/* +* Pipe Output Buffer +* (C) 1999-2007,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Read data from a message +*/ +size_t Output_Buffers::read(byte output[], size_t length, + Pipe::message_id msg) + { + SecureQueue* q = get(msg); + if(q) + return q->read(output, length); + return 0; + } + +/* +* Peek at data in a message +*/ +size_t Output_Buffers::peek(byte output[], size_t length, + size_t stream_offset, + Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->peek(output, length, stream_offset); + return 0; + } + +/* +* Check available bytes in a message +*/ +size_t Output_Buffers::remaining(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->size(); + return 0; + } + +/* +* Add a new output queue +*/ +void Output_Buffers::add(SecureQueue* queue) + { + BOTAN_ASSERT(queue, "argument was NULL"); + + BOTAN_ASSERT(buffers.size() < buffers.max_size(), + "No more room in container"); + + buffers.push_back(queue); + } + +/* +* Retire old output queues +*/ +void Output_Buffers::retire() + { + for(size_t i = 0; i != buffers.size(); ++i) + if(buffers[i] && buffers[i]->size() == 0) + { + delete buffers[i]; + buffers[i] = 0; + } + + while(buffers.size() && !buffers[0]) + { + buffers.pop_front(); + offset = offset + Pipe::message_id(1); + } + } + +/* +* Get a particular output queue +*/ +SecureQueue* Output_Buffers::get(Pipe::message_id msg) const + { + if(msg < offset) + return 0; + + BOTAN_ASSERT(msg < message_count(), + "Message number out of range"); + + return buffers[msg-offset]; + } + +/* +* Return the total number of messages +*/ +Pipe::message_id Output_Buffers::message_count() const + { + return (offset + buffers.size()); + } + +/* +* Output_Buffers Constructor +*/ +Output_Buffers::Output_Buffers() + { + offset = 0; + } + +/* +* Output_Buffers Destructor +*/ +Output_Buffers::~Output_Buffers() + { + for(size_t j = 0; j != buffers.size(); ++j) + delete buffers[j]; + } + +} +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* A Filter that does nothing +*/ +class Null_Filter : public Filter + { + public: + void write(const byte input[], size_t length) + { send(input, length); } + + std::string name() const { return "Null"; } + }; + +} + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + init(); + append(f1); + append(f2); + append(f3); + append(f4); + } + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* filter_array[], size_t count) + { + init(); + for(size_t j = 0; j != count; ++j) + append(filter_array[j]); + } + +/* +* Pipe Destructor +*/ +Pipe::~Pipe() + { + destruct(pipe); + delete outputs; + } + +/* +* Initialize the Pipe +*/ +void Pipe::init() + { + outputs = new Output_Buffers; + pipe = 0; + default_read = 0; + inside_msg = false; + } + +/* +* Reset the Pipe +*/ +void Pipe::reset() + { + destruct(pipe); + pipe = 0; + inside_msg = false; + } + +/* +* Destroy the Pipe +*/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast(to_kill)) + return; + for(size_t j = 0; j != to_kill->total_ports(); ++j) + destruct(to_kill->next[j]); + delete to_kill; + } + +/* +* Test if the Pipe has any data in it +*/ +bool Pipe::end_of_data() const + { + return (remaining() == 0); + } + +/* +* Set the default read message +*/ +void Pipe::set_default_msg(message_id msg) + { + if(msg >= message_count()) + throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); + default_read = msg; + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const byte input[], size_t length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const MemoryRegion& input) + { + process_msg(&input[0], input.size()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const std::string& input) + { + process_msg(reinterpret_cast(input.data()), input.length()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(DataSource& input) + { + start_msg(); + write(input); + end_msg(); + } + +/* +* Start a new message +*/ +void Pipe::start_msg() + { + if(inside_msg) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(pipe == 0) + pipe = new Null_Filter; + find_endpoints(pipe); + pipe->new_msg(); + inside_msg = true; + } + +/* +* End the current message +*/ +void Pipe::end_msg() + { + if(!inside_msg) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + pipe->finish_msg(); + clear_endpoints(pipe); + if(dynamic_cast(pipe)) + { + delete pipe; + pipe = 0; + } + inside_msg = false; + + outputs->retire(); + } + +/* +* Find the endpoints of the Pipe +*/ +void Pipe::find_endpoints(Filter* f) + { + for(size_t j = 0; j != f->total_ports(); ++j) + if(f->next[j] && !dynamic_cast(f->next[j])) + find_endpoints(f->next[j]); + else + { + SecureQueue* q = new SecureQueue; + f->next[j] = q; + outputs->add(q); + } + } + +/* +* Remove the SecureQueues attached to the Filter +*/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(size_t j = 0; j != f->total_ports(); ++j) + { + if(f->next[j] && dynamic_cast(f->next[j])) + f->next[j] = 0; + clear_endpoints(f->next[j]); + } + } + +/* +* Append a Filter to the Pipe +*/ +void Pipe::append(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot append to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(!pipe) pipe = filter; + else pipe->attach(filter); + } + +/* +* Prepend a Filter to the Pipe +*/ +void Pipe::prepend(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot prepend to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(pipe) filter->attach(pipe); + pipe = filter; + } + +/* +* Pop a Filter off the Pipe +*/ +void Pipe::pop() + { + if(inside_msg) + throw Invalid_State("Cannot pop off a Pipe while it is processing"); + + if(!pipe) + return; + + if(pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + + Filter* f = pipe; + size_t owns = f->owns(); + pipe = pipe->next[0]; + delete f; + + while(owns--) + { + f = pipe; + pipe = pipe->next[0]; + delete f; + } + } + +/* +* Return the number of messages in this Pipe +*/ +Pipe::message_id Pipe::message_count() const + { + return outputs->message_count(); + } + +/* +* Static Member Variables +*/ +const Pipe::message_id Pipe::LAST_MESSAGE = + static_cast(-2); + +const Pipe::message_id Pipe::DEFAULT_MESSAGE = + static_cast(-1); + +} +/* +* Pipe I/O +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Write data from a pipe into an ostream +*/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(stream.good() && pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + stream.write(reinterpret_cast(&buffer[0]), got); + } + if(!stream.good()) + throw Stream_IO_Error("Pipe output operator (iostream) has failed"); + return stream; + } + +/* +* Read data from an istream into a pipe +*/ +std::istream& operator>>(std::istream& stream, Pipe& pipe) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(stream.good()) + { + stream.read(reinterpret_cast(&buffer[0]), buffer.size()); + pipe.write(&buffer[0], stream.gcount()); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} +/* +* Pipe Reading/Writing +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Look up the canonical ID for a queue +*/ +Pipe::message_id Pipe::get_message_no(const std::string& func_name, + message_id msg) const + { + if(msg == DEFAULT_MESSAGE) + msg = default_msg(); + else if(msg == LAST_MESSAGE) + msg = message_count() - 1; + + if(msg >= message_count()) + throw Invalid_Message_Number(func_name, msg); + + return msg; + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const byte input[], size_t length) + { + if(!inside_msg) + throw Invalid_State("Cannot write to a Pipe while it is not processing"); + pipe->write(input, length); + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const MemoryRegion& input) + { + write(&input[0], input.size()); + } + +/* +* Write a string into a Pipe +*/ +void Pipe::write(const std::string& str) + { + write(reinterpret_cast(str.data()), str.size()); + } + +/* +* Write a single byte into a Pipe +*/ +void Pipe::write(byte input) + { + write(&input, 1); + } + +/* +* Write the contents of a DataSource into a Pipe +*/ +void Pipe::write(DataSource& source) + { + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(!source.end_of_data()) + { + size_t got = source.read(&buffer[0], buffer.size()); + write(&buffer[0], got); + } + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(byte output[], size_t length, message_id msg) + { + return outputs->read(output, length, get_message_no("read", msg)); + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(byte output[], size_t length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/* +* Read a single byte from the pipe +*/ +size_t Pipe::read(byte& out, message_id msg) + { + return read(&out, 1, msg); + } + +/* +* Return all data in the pipe +*/ +SecureVector Pipe::read_all(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector buffer(remaining(msg)); + size_t got = read(&buffer[0], buffer.size(), msg); + buffer.resize(got); + return buffer; + } + +/* +* Return all data in the pipe as a string +*/ +std::string Pipe::read_all_as_string(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector buffer(DEFAULT_BUFFERSIZE); + std::string str; + str.reserve(remaining(msg)); + + while(true) + { + size_t got = read(&buffer[0], buffer.size(), msg); + if(got == 0) + break; + str.append(reinterpret_cast(&buffer[0]), got); + } + + return str; + } + +/* +* Find out how many bytes are ready to read +*/ +size_t Pipe::remaining(message_id msg) const + { + return outputs->remaining(get_message_no("remaining", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(byte output[], size_t length, + size_t offset, message_id msg) const + { + return outputs->peek(output, length, offset, get_message_no("peek", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(byte output[], size_t length, size_t offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/* +* Peek at a byte in the pipe +*/ +size_t Pipe::peek(byte& out, size_t offset, message_id msg) const + { + return peek(&out, 1, offset, msg); + } + +} +/* +* PK Filters +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Append to the buffer +*/ +void PK_Encryptor_Filter::write(const byte input[], size_t length) + { + buffer += std::make_pair(input, length); + } + +/* +* Encrypt the message +*/ +void PK_Encryptor_Filter::end_msg() + { + send(cipher->encrypt(buffer, rng)); + buffer.clear(); + } + +/* +* Append to the buffer +*/ +void PK_Decryptor_Filter::write(const byte input[], size_t length) + { + buffer += std::make_pair(input, length); + } + +/* +* Decrypt the message +*/ +void PK_Decryptor_Filter::end_msg() + { + send(cipher->decrypt(buffer)); + buffer.clear(); + } + +/* +* Add more data +*/ +void PK_Signer_Filter::write(const byte input[], size_t length) + { + signer->update(input, length); + } + +/* +* Sign the message +*/ +void PK_Signer_Filter::end_msg() + { + send(signer->signature(rng)); + } + +/* +* Add more data +*/ +void PK_Verifier_Filter::write(const byte input[], size_t length) + { + verifier->update(input, length); + } + +/* +* Verify the message +*/ +void PK_Verifier_Filter::end_msg() + { + if(signature.empty()) + throw Invalid_State("PK_Verifier_Filter: No signature to check against"); + bool is_valid = verifier->check_signature(signature); + send((is_valid ? 1 : 0)); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const byte sig[], size_t length) + { + signature.resize(length); + copy_mem(&signature[0], sig, length); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const MemoryRegion& sig) + { + signature = sig; + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, const byte sig[], + size_t length) : + verifier(v), signature(sig, length) + { + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, + const MemoryRegion& sig) : + verifier(v), signature(sig) + { + } + +} +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* A node in a SecureQueue +*/ +class SecureQueueNode + { + public: + SecureQueueNode() : buffer(DEFAULT_BUFFERSIZE) + { next = 0; start = end = 0; } + + ~SecureQueueNode() { next = 0; start = end = 0; } + + size_t write(const byte input[], size_t length) + { + size_t copied = std::min(length, buffer.size() - end); + copy_mem(&buffer[end], input, copied); + end += copied; + return copied; + } + + size_t read(byte output[], size_t length) + { + size_t copied = std::min(length, end - start); + copy_mem(output, &buffer[start], copied); + start += copied; + return copied; + } + + size_t peek(byte output[], size_t length, size_t offset = 0) + { + const size_t left = end - start; + if(offset >= left) return 0; + size_t copied = std::min(length, left - offset); + copy_mem(output, &buffer[start + offset], copied); + return copied; + } + + size_t size() const { return (end - start); } + private: + friend class SecureQueue; + SecureQueueNode* next; + SecureVector buffer; + size_t start, end; + }; + +/* +* Create a SecureQueue +*/ +SecureQueue::SecureQueue() + { + set_next(0, 0); + head = tail = new SecureQueueNode; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue::SecureQueue(const SecureQueue& input) : + Fanout_Filter(), DataSource() + { + set_next(0, 0); + + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(&temp->buffer[temp->start], temp->end - temp->start); + temp = temp->next; + } + } + +/* +* Destroy this SecureQueue +*/ +void SecureQueue::destroy() + { + SecureQueueNode* temp = head; + while(temp) + { + SecureQueueNode* holder = temp->next; + delete temp; + temp = holder; + } + head = tail = 0; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue& SecureQueue::operator=(const SecureQueue& input) + { + destroy(); + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(&temp->buffer[temp->start], temp->end - temp->start); + temp = temp->next; + } + return (*this); + } + +/* +* Add some bytes to the queue +*/ +void SecureQueue::write(const byte input[], size_t length) + { + if(!head) + head = tail = new SecureQueueNode; + while(length) + { + const size_t n = tail->write(input, length); + input += n; + length -= n; + if(length) + { + tail->next = new SecureQueueNode; + tail = tail->next; + } + } + } + +/* +* Read some bytes from the queue +*/ +size_t SecureQueue::read(byte output[], size_t length) + { + size_t got = 0; + while(length && head) + { + const size_t n = head->read(output, length); + output += n; + got += n; + length -= n; + if(head->size() == 0) + { + SecureQueueNode* holder = head->next; + delete head; + head = holder; + } + } + return got; + } + +/* +* Read data, but do not remove it from queue +*/ +size_t SecureQueue::peek(byte output[], size_t length, size_t offset) const + { + SecureQueueNode* current = head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->next; + } + else + break; + } + + size_t got = 0; + while(length && current) + { + const size_t n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->next; + } + return got; + } + +/* +* Return how many bytes the queue holds +*/ +size_t SecureQueue::size() const + { + SecureQueueNode* current = head; + size_t count = 0; + + while(current) + { + count += current->size(); + current = current->next; + } + return count; + } + +/* +* Test if the queue has any data in it +*/ +bool SecureQueue::end_of_data() const + { + return (size() == 0); + } + +} +/* +* Blue Midnight Wish 512 (Round 2 tweaked) +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +inline u64bit S0(u64bit X) + { + return (X >> 1) ^ (X << 3) ^ rotate_left(X, 4) ^ rotate_left(X, 37); + } + +inline u64bit S1(u64bit X) + { + return (X >> 1) ^ (X << 2) ^ rotate_left(X, 13) ^ rotate_left(X, 43); + } + +inline u64bit S2(u64bit X) + { + return (X >> 2) ^ (X << 1) ^ rotate_left(X, 19) ^ rotate_left(X, 53); + } + +inline u64bit S3(u64bit X) + { + return (X >> 2) ^ (X << 2) ^ rotate_left(X, 28) ^ rotate_left(X, 59); + } + +inline u64bit S4(u64bit X) + { + return (X >> 1) ^ X; + } + +/** +* Blue Midnight Wish 512 compression function +*/ +void BMW_512_compress(u64bit H[16], const u64bit M[16], u64bit Q[32]) + { + const size_t EXPAND_1_ROUNDS = 2; + + for(size_t i = 0; i != 16; ++i) + Q[i] = H[i] ^ M[i]; + + Q[16] = Q[ 5] - Q[ 7] + Q[10] + Q[13] + Q[14]; + Q[17] = Q[ 6] - Q[ 8] + Q[11] + Q[14] - Q[15]; + Q[18] = Q[ 0] + Q[ 7] + Q[ 9] - Q[12] + Q[15]; + Q[19] = Q[ 0] - Q[ 1] + Q[ 8] - Q[10] + Q[13]; + Q[20] = Q[ 1] + Q[ 2] + Q[ 9] - Q[11] - Q[14]; + Q[21] = Q[ 3] - Q[ 2] + Q[10] - Q[12] + Q[15]; + Q[22] = Q[ 4] - Q[ 0] - Q[ 3] - Q[11] + Q[13]; + Q[23] = Q[ 1] - Q[ 4] - Q[ 5] - Q[12] - Q[14]; + Q[24] = Q[ 2] - Q[ 5] - Q[ 6] + Q[13] - Q[15]; + Q[25] = Q[ 0] - Q[ 3] + Q[ 6] - Q[ 7] + Q[14]; + Q[26] = Q[ 8] - Q[ 1] - Q[ 4] - Q[ 7] + Q[15]; + Q[27] = Q[ 8] - Q[ 0] - Q[ 2] - Q[ 5] + Q[ 9]; + Q[28] = Q[ 1] + Q[ 3] - Q[ 6] - Q[ 9] + Q[10]; + Q[29] = Q[ 2] + Q[ 4] + Q[ 7] + Q[10] + Q[11]; + Q[30] = Q[ 3] - Q[ 5] + Q[ 8] - Q[11] - Q[12]; + Q[31] = Q[12] - Q[ 4] - Q[ 6] - Q[ 9] + Q[13]; + + Q[ 0] = S0(Q[16]) + H[ 1]; + Q[ 1] = S1(Q[17]) + H[ 2]; + Q[ 2] = S2(Q[18]) + H[ 3]; + Q[ 3] = S3(Q[19]) + H[ 4]; + Q[ 4] = S4(Q[20]) + H[ 5]; + Q[ 5] = S0(Q[21]) + H[ 6]; + Q[ 6] = S1(Q[22]) + H[ 7]; + Q[ 7] = S2(Q[23]) + H[ 8]; + Q[ 8] = S3(Q[24]) + H[ 9]; + Q[ 9] = S4(Q[25]) + H[10]; + Q[10] = S0(Q[26]) + H[11]; + Q[11] = S1(Q[27]) + H[12]; + Q[12] = S2(Q[28]) + H[13]; + Q[13] = S3(Q[29]) + H[14]; + Q[14] = S4(Q[30]) + H[15]; + Q[15] = S0(Q[31]) + H[ 0]; + + for(size_t i = 16; i != 16 + EXPAND_1_ROUNDS; ++i) + { + Q[i] = S1(Q[i-16]) + S2(Q[i-15]) + S3(Q[i-14]) + S0(Q[i-13]) + + S1(Q[i-12]) + S2(Q[i-11]) + S3(Q[i-10]) + S0(Q[i- 9]) + + S1(Q[i- 8]) + S2(Q[i- 7]) + S3(Q[i- 6]) + S0(Q[i- 5]) + + S1(Q[i- 4]) + S2(Q[i- 3]) + S3(Q[i- 2]) + S0(Q[i- 1]) + + ((rotate_left(M[(i-16) % 16], ((i-16)%16) + 1) + + rotate_left(M[(i-13) % 16], ((i-13)%16) + 1) - + rotate_left(M[(i- 6) % 16], ((i-6)%16) + 1) + + (0x0555555555555555ULL * i)) ^ H[(i-16+7)%16]); + } + + for(size_t i = 16 + EXPAND_1_ROUNDS; i != 32; ++i) + { + Q[i] = Q[i-16] + rotate_left(Q[i-15], 5) + + Q[i-14] + rotate_left(Q[i-13], 11) + + Q[i-12] + rotate_left(Q[i-11], 27) + + Q[i-10] + rotate_left(Q[i- 9], 32) + + Q[i- 8] + rotate_left(Q[i- 7], 37) + + Q[i- 6] + rotate_left(Q[i- 5], 43) + + Q[i- 4] + rotate_left(Q[i- 3], 53) + + S4(Q[i - 2]) + ((Q[i-1] >> 2) ^ Q[i-1]) + + ((rotate_left(M[(i-16) % 16], ((i-16)%16 + 1)) + + rotate_left(M[(i-13) % 16], ((i-13)%16 + 1)) - + rotate_left(M[(i- 6) % 16], ((i-6)%16 + 1)) + + (0x0555555555555555ULL * i)) ^ H[(i-16+7)%16]); + } + + u64bit XL = Q[16] ^ Q[17] ^ Q[18] ^ Q[19] ^ + Q[20] ^ Q[21] ^ Q[22] ^ Q[23]; + + u64bit XH = Q[24] ^ Q[25] ^ Q[26] ^ Q[27] ^ + Q[28] ^ Q[29] ^ Q[30] ^ Q[31]; + + XH ^= XL; + + H[ 0] = ((XH << 5) ^ (Q[16] >> 5) ^ M[0]) + (XL ^ Q[24] ^ Q[0]); + H[ 1] = ((XH >> 7) ^ (Q[17] << 8) ^ M[1]) + (XL ^ Q[25] ^ Q[1]); + H[ 2] = ((XH >> 5) ^ (Q[18] << 5) ^ M[2]) + (XL ^ Q[26] ^ Q[2]); + H[ 3] = ((XH >> 1) ^ (Q[19] << 5) ^ M[3]) + (XL ^ Q[27] ^ Q[3]); + H[ 4] = ((XH >> 3) ^ (Q[20] ) ^ M[4]) + (XL ^ Q[28] ^ Q[4]); + H[ 5] = ((XH << 6) ^ (Q[21] >> 6) ^ M[5]) + (XL ^ Q[29] ^ Q[5]); + H[ 6] = ((XH >> 4) ^ (Q[22] << 6) ^ M[6]) + (XL ^ Q[30] ^ Q[6]); + H[ 7] = ((XH >> 11) ^ (Q[23] << 2) ^ M[7]) + (XL ^ Q[31] ^ Q[7]); + + H[ 8] = rotate_left(H[4], 9) + (XH ^ Q[24] ^ M[ 8]) + ((XL << 8) ^ Q[23] ^ Q[ 8]); + H[ 9] = rotate_left(H[5], 10) + (XH ^ Q[25] ^ M[ 9]) + ((XL >> 6) ^ Q[16] ^ Q[ 9]); + H[10] = rotate_left(H[6], 11) + (XH ^ Q[26] ^ M[10]) + ((XL << 6) ^ Q[17] ^ Q[10]); + H[11] = rotate_left(H[7], 12) + (XH ^ Q[27] ^ M[11]) + ((XL << 4) ^ Q[18] ^ Q[11]); + H[12] = rotate_left(H[0], 13) + (XH ^ Q[28] ^ M[12]) + ((XL >> 3) ^ Q[19] ^ Q[12]); + H[13] = rotate_left(H[1], 14) + (XH ^ Q[29] ^ M[13]) + ((XL >> 4) ^ Q[20] ^ Q[13]); + H[14] = rotate_left(H[2], 15) + (XH ^ Q[30] ^ M[14]) + ((XL >> 7) ^ Q[21] ^ Q[14]); + H[15] = rotate_left(H[3], 16) + (XH ^ Q[31] ^ M[15]) + ((XL >> 2) ^ Q[22] ^ Q[15]); + } + +} + +void BMW_512::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + BMW_512_compress(&H[0], &M[0], &Q[0]); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void BMW_512::copy_out(byte output[]) + { + u64bit final[16] = { + 0xAAAAAAAAAAAAAAA0ULL, 0xAAAAAAAAAAAAAAA1ULL, + 0xAAAAAAAAAAAAAAA2ULL, 0xAAAAAAAAAAAAAAA3ULL, + 0xAAAAAAAAAAAAAAA4ULL, 0xAAAAAAAAAAAAAAA5ULL, + 0xAAAAAAAAAAAAAAA6ULL, 0xAAAAAAAAAAAAAAA7ULL, + 0xAAAAAAAAAAAAAAA8ULL, 0xAAAAAAAAAAAAAAA9ULL, + 0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAABULL, + 0xAAAAAAAAAAAAAAACULL, 0xAAAAAAAAAAAAAAADULL, + 0xAAAAAAAAAAAAAAAEULL, 0xAAAAAAAAAAAAAAAFULL }; + + BMW_512_compress(final, &H[0], &Q[0]); + + for(size_t i = 0; i != output_length(); i += 8) + store_le(final[8 + i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void BMW_512::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + zeroise(Q); + + H[ 0] = 0x8081828384858687ULL; + H[ 1] = 0x88898A8B8C8D8E8FULL; + H[ 2] = 0x9091929394959697ULL; + H[ 3] = 0x98999A9B9C9D9E9FULL; + H[ 4] = 0xA0A1A2A3A4A5A6A7ULL; + H[ 5] = 0xA8A9AAABACADAEAFULL; + H[ 6] = 0xB0B1B2B3B4B5B6B7ULL; + H[ 7] = 0xB8B9BABBBCBDBEBFULL; + H[ 8] = 0xC0C1C2C3C4C5C6C7ULL; + H[ 9] = 0xC8C9CACBCCCDCECFULL; + H[10] = 0xD0D1D2D3D4D5D6D7ULL; + H[11] = 0xD8D9DADBDCDDDEDFULL; + H[12] = 0xE0E1E2E3E4E5E6E7ULL; + H[13] = 0xE8E9EAEBECEDEEEFULL; + H[14] = 0xF0F1F2F3F4F5F6F7ULL; + H[15] = 0xF8F9FAFBFCFDFEFFULL; + } + +} +/* +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +void comb4p_round(MemoryRegion& out, + const MemoryRegion& in, + byte round_no, + HashFunction* h1, + HashFunction* h2) + { + h1->update(round_no); + h2->update(round_no); + + h1->update(&in[0], in.size()); + h2->update(&in[0], in.size()); + + SecureVector h_buf = h1->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + + h_buf = h2->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + } + +} + +Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) : + hash1(h1), hash2(h2) + { + if(hash1->name() == hash2->name()) + throw std::invalid_argument("Comb4P: Must use two distinct hashes"); + + if(hash1->output_length() != hash2->output_length()) + throw std::invalid_argument("Comb4P: Incompatible hashes " + + hash1->name() + " and " + + hash2->name()); + + clear(); + } + +size_t Comb4P::hash_block_size() const + { + if(hash1->hash_block_size() == hash2->hash_block_size()) + return hash1->hash_block_size(); + + /* + * Return LCM of the block sizes? This would probably be OK for + * HMAC, which is the main thing relying on knowing the block size. + */ + return 0; + } + +void Comb4P::clear() + { + hash1->clear(); + hash2->clear(); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +void Comb4P::add_data(const byte input[], size_t length) + { + hash1->update(input, length); + hash2->update(input, length); + } + +void Comb4P::final_result(byte out[]) + { + SecureVector h1 = hash1->final(); + SecureVector h2 = hash2->final(); + + // First round + xor_buf(&h1[0], &h2[0], std::min(h1.size(), h2.size())); + + // Second round + comb4p_round(h2, h1, 1, hash1, hash2); + + // Third round + comb4p_round(h1, h2, 2, hash1, hash2); + + copy_mem(out , &h1[0], h1.size()); + copy_mem(out + h1.size(), &h2[0], h2.size()); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +} + +/* +* GOST 34.11 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/** +* GOST 34.11 Constructor +*/ +GOST_34_11::GOST_34_11() : + cipher(GOST_28147_89_Params("R3411_CryptoPro")), + buffer(32), + sum(32), + hash(32) + { + count = 0; + position = 0; + } + +void GOST_34_11::clear() + { + cipher.clear(); + zeroise(sum); + zeroise(hash); + count = 0; + position = 0; + } + +/** +* Hash additional inputs +*/ +void GOST_34_11::add_data(const byte input[], size_t length) + { + count += length; + + if(position) + { + buffer.copy(position, input, length); + + if(position + length >= hash_block_size()) + { + compress_n(&buffer[0], 1); + input += (hash_block_size() - position); + length -= (hash_block_size() - position); + position = 0; + } + } + + const size_t full_blocks = length / hash_block_size(); + const size_t remaining = length % hash_block_size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer.copy(position, input + full_blocks * hash_block_size(), remaining); + position += remaining; + } + +/** +* The GOST 34.11 compression function +*/ +void GOST_34_11::compress_n(const byte input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + for(u16bit j = 0, carry = 0; j != 32; ++j) + { + u16bit s = sum[j] + input[32*i+j] + carry; + carry = get_byte(0, s); + sum[j] = get_byte(1, s); + } + + byte S[32] = { 0 }; + + u64bit U[4], V[4]; + load_be(U, &hash[0], 4); + load_be(V, input + 32*i, 4); + + for(size_t j = 0; j != 4; ++j) + { + byte key[32] = { 0 }; + + // P transformation + for(size_t k = 0; k != 4; ++k) + for(size_t l = 0; l != 8; ++l) + key[4*l+k] = get_byte(l, U[k]) ^ get_byte(l, V[k]); + + cipher.set_key(key, 32); + cipher.encrypt(&hash[8*j], S + 8*j); + + if(j == 3) + break; + + // A(x) + u64bit A_U = U[0]; + U[0] = U[1]; + U[1] = U[2]; + U[2] = U[3]; + U[3] = U[0] ^ A_U; + + if(j == 1) // C_3 + { + U[0] ^= 0x00FF00FF00FF00FFULL; + U[1] ^= 0xFF00FF00FF00FF00ULL; + U[2] ^= 0x00FFFF00FF0000FFULL; + U[3] ^= 0xFF000000FFFF00FFULL; + } + + // A(A(x)) + u64bit AA_V_1 = V[0] ^ V[1]; + u64bit AA_V_2 = V[1] ^ V[2]; + V[0] = V[2]; + V[1] = V[3]; + V[2] = AA_V_1; + V[3] = AA_V_2; + } + + byte S2[32] = { 0 }; + + // 12 rounds of psi + S2[ 0] = S[24]; + S2[ 1] = S[25]; + S2[ 2] = S[26]; + S2[ 3] = S[27]; + S2[ 4] = S[28]; + S2[ 5] = S[29]; + S2[ 6] = S[30]; + S2[ 7] = S[31]; + S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31]; + S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30]; + S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31]; + S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28]; + S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29]; + S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30]; + S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31]; + S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28]; + S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29]; + S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30]; + S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26]; + S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27]; + S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28]; + S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29]; + S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28]; + S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29]; + + xor_buf(S, S2, input + 32*i, 32); + + S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30]; + S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31]; + + copy_mem(S, S+2, 30); + S[30] = S2[0]; + S[31] = S2[1]; + + xor_buf(S, &hash[0], 32); + + // 61 rounds of psi + S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28]; + S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29]; + S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30]; + S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31]; + S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30]; + S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31]; + S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28]; + S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29]; + S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30]; + S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24]; + S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25]; + S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26]; + S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27]; + S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28]; + S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29]; + S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30]; + S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^ + S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^ + S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^ + S[24] ^ S[26] ^ S[28]; + S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^ + S[25] ^ S[27] ^ S[29]; + S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ + S[26] ^ S[28] ^ S[30]; + S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ + S[27] ^ S[29] ^ S[31]; + S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28]; + S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29]; + S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30]; + S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31]; + + hash.copy(S2, 32); + } + } + +/** +* Produce the final GOST 34.11 output +*/ +void GOST_34_11::final_result(byte out[]) + { + if(position) + { + clear_mem(&buffer[0] + position, buffer.size() - position); + compress_n(&buffer[0], 1); + } + + SecureVector length_buf(32); + const u64bit bit_count = count * 8; + store_le(bit_count, &length_buf[0]); + + SecureVector sum_buf = sum; + + compress_n(&length_buf[0], 1); + compress_n(&sum_buf[0], 1); + + copy_mem(out, &hash[0], 32); + + clear(); + } + +} +/* +* HAS-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace HAS_160_F { + +/* +* HAS-160 F1 Function +*/ +inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (D ^ (B & (C ^ D))) + msg; + B = rotate_left(B, 10); + } + +/* +* HAS-160 F2 Function +*/ +inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x5A827999; + B = rotate_left(B, 17); + } + +/* +* HAS-160 F3 Function +*/ +inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (C ^ (B | ~D)) + msg + 0x6ED9EBA1; + B = rotate_left(B, 25); + } + +/* +* HAS-160 F4 Function +*/ +inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, + u32bit msg, u32bit rot) + { + E += rotate_left(A, rot) + (B ^ C ^ D) + msg + 0x8F1BBCDC; + B = rotate_left(B, 30); + } + +} + +/* +* HAS-160 Compression Function +*/ +void HAS_160::compress_n(const byte input[], size_t blocks) + { + using namespace HAS_160_F; + + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&X[0], input, 16); + + X[16] = X[ 0] ^ X[ 1] ^ X[ 2] ^ X[ 3]; + X[17] = X[ 4] ^ X[ 5] ^ X[ 6] ^ X[ 7]; + X[18] = X[ 8] ^ X[ 9] ^ X[10] ^ X[11]; + X[19] = X[12] ^ X[13] ^ X[14] ^ X[15]; + F1(A,B,C,D,E,X[18], 5); F1(E,A,B,C,D,X[ 0],11); + F1(D,E,A,B,C,X[ 1], 7); F1(C,D,E,A,B,X[ 2],15); + F1(B,C,D,E,A,X[ 3], 6); F1(A,B,C,D,E,X[19],13); + F1(E,A,B,C,D,X[ 4], 8); F1(D,E,A,B,C,X[ 5],14); + F1(C,D,E,A,B,X[ 6], 7); F1(B,C,D,E,A,X[ 7],12); + F1(A,B,C,D,E,X[16], 9); F1(E,A,B,C,D,X[ 8],11); + F1(D,E,A,B,C,X[ 9], 8); F1(C,D,E,A,B,X[10],15); + F1(B,C,D,E,A,X[11], 6); F1(A,B,C,D,E,X[17],12); + F1(E,A,B,C,D,X[12], 9); F1(D,E,A,B,C,X[13],14); + F1(C,D,E,A,B,X[14], 5); F1(B,C,D,E,A,X[15],13); + + X[16] = X[ 3] ^ X[ 6] ^ X[ 9] ^ X[12]; + X[17] = X[ 2] ^ X[ 5] ^ X[ 8] ^ X[15]; + X[18] = X[ 1] ^ X[ 4] ^ X[11] ^ X[14]; + X[19] = X[ 0] ^ X[ 7] ^ X[10] ^ X[13]; + F2(A,B,C,D,E,X[18], 5); F2(E,A,B,C,D,X[ 3],11); + F2(D,E,A,B,C,X[ 6], 7); F2(C,D,E,A,B,X[ 9],15); + F2(B,C,D,E,A,X[12], 6); F2(A,B,C,D,E,X[19],13); + F2(E,A,B,C,D,X[15], 8); F2(D,E,A,B,C,X[ 2],14); + F2(C,D,E,A,B,X[ 5], 7); F2(B,C,D,E,A,X[ 8],12); + F2(A,B,C,D,E,X[16], 9); F2(E,A,B,C,D,X[11],11); + F2(D,E,A,B,C,X[14], 8); F2(C,D,E,A,B,X[ 1],15); + F2(B,C,D,E,A,X[ 4], 6); F2(A,B,C,D,E,X[17],12); + F2(E,A,B,C,D,X[ 7], 9); F2(D,E,A,B,C,X[10],14); + F2(C,D,E,A,B,X[13], 5); F2(B,C,D,E,A,X[ 0],13); + + X[16] = X[ 5] ^ X[ 7] ^ X[12] ^ X[14]; + X[17] = X[ 0] ^ X[ 2] ^ X[ 9] ^ X[11]; + X[18] = X[ 4] ^ X[ 6] ^ X[13] ^ X[15]; + X[19] = X[ 1] ^ X[ 3] ^ X[ 8] ^ X[10]; + F3(A,B,C,D,E,X[18], 5); F3(E,A,B,C,D,X[12],11); + F3(D,E,A,B,C,X[ 5], 7); F3(C,D,E,A,B,X[14],15); + F3(B,C,D,E,A,X[ 7], 6); F3(A,B,C,D,E,X[19],13); + F3(E,A,B,C,D,X[ 0], 8); F3(D,E,A,B,C,X[ 9],14); + F3(C,D,E,A,B,X[ 2], 7); F3(B,C,D,E,A,X[11],12); + F3(A,B,C,D,E,X[16], 9); F3(E,A,B,C,D,X[ 4],11); + F3(D,E,A,B,C,X[13], 8); F3(C,D,E,A,B,X[ 6],15); + F3(B,C,D,E,A,X[15], 6); F3(A,B,C,D,E,X[17],12); + F3(E,A,B,C,D,X[ 8], 9); F3(D,E,A,B,C,X[ 1],14); + F3(C,D,E,A,B,X[10], 5); F3(B,C,D,E,A,X[ 3],13); + + X[16] = X[ 2] ^ X[ 7] ^ X[ 8] ^ X[13]; + X[17] = X[ 3] ^ X[ 4] ^ X[ 9] ^ X[14]; + X[18] = X[ 0] ^ X[ 5] ^ X[10] ^ X[15]; + X[19] = X[ 1] ^ X[ 6] ^ X[11] ^ X[12]; + F4(A,B,C,D,E,X[18], 5); F4(E,A,B,C,D,X[ 7],11); + F4(D,E,A,B,C,X[ 2], 7); F4(C,D,E,A,B,X[13],15); + F4(B,C,D,E,A,X[ 8], 6); F4(A,B,C,D,E,X[19],13); + F4(E,A,B,C,D,X[ 3], 8); F4(D,E,A,B,C,X[14],14); + F4(C,D,E,A,B,X[ 9], 7); F4(B,C,D,E,A,X[ 4],12); + F4(A,B,C,D,E,X[16], 9); F4(E,A,B,C,D,X[15],11); + F4(D,E,A,B,C,X[10], 8); F4(C,D,E,A,B,X[ 5],15); + F4(B,C,D,E,A,X[ 0], 6); F4(A,B,C,D,E,X[17],12); + F4(E,A,B,C,D,X[11], 9); F4(D,E,A,B,C,X[ 6],14); + F4(C,D,E,A,B,X[ 1], 5); F4(B,C,D,E,A,X[12],13); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void HAS_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void HAS_160::clear() + { + MDx_HashFunction::clear(); + zeroise(X); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} +/* +* Keccak +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +void keccak_f_1600(u64bit A[25]) + { + static const u64bit RC[24] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808AULL, + 0x8000000080008000ULL, 0x000000000000808BULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008AULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000AULL, + 0x000000008000808BULL, 0x800000000000008BULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800AULL, 0x800000008000000AULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL + }; + + for(size_t i = 0; i != 24; ++i) + { + const u64bit C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20]; + const u64bit C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21]; + const u64bit C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22]; + const u64bit C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23]; + const u64bit C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]; + + const u64bit D0 = rotate_left(C0, 1) ^ C3; + const u64bit D1 = rotate_left(C1, 1) ^ C4; + const u64bit D2 = rotate_left(C2, 1) ^ C0; + const u64bit D3 = rotate_left(C3, 1) ^ C1; + const u64bit D4 = rotate_left(C4, 1) ^ C2; + + const u64bit B00 = A[ 0] ^ D1; + const u64bit B01 = rotate_left(A[ 6] ^ D2, 44); + const u64bit B02 = rotate_left(A[12] ^ D3, 43); + const u64bit B03 = rotate_left(A[18] ^ D4, 21); + const u64bit B04 = rotate_left(A[24] ^ D0, 14); + const u64bit B05 = rotate_left(A[ 3] ^ D4, 28); + const u64bit B06 = rotate_left(A[ 9] ^ D0, 20); + const u64bit B07 = rotate_left(A[10] ^ D1, 3); + const u64bit B08 = rotate_left(A[16] ^ D2, 45); + const u64bit B09 = rotate_left(A[22] ^ D3, 61); + const u64bit B10 = rotate_left(A[ 1] ^ D2, 1); + const u64bit B11 = rotate_left(A[ 7] ^ D3, 6); + const u64bit B12 = rotate_left(A[13] ^ D4, 25); + const u64bit B13 = rotate_left(A[19] ^ D0, 8); + const u64bit B14 = rotate_left(A[20] ^ D1, 18); + const u64bit B15 = rotate_left(A[ 4] ^ D0, 27); + const u64bit B16 = rotate_left(A[ 5] ^ D1, 36); + const u64bit B17 = rotate_left(A[11] ^ D2, 10); + const u64bit B18 = rotate_left(A[17] ^ D3, 15); + const u64bit B19 = rotate_left(A[23] ^ D4, 56); + const u64bit B20 = rotate_left(A[ 2] ^ D3, 62); + const u64bit B21 = rotate_left(A[ 8] ^ D4, 55); + const u64bit B22 = rotate_left(A[14] ^ D0, 39); + const u64bit B23 = rotate_left(A[15] ^ D1, 41); + const u64bit B24 = rotate_left(A[21] ^ D2, 2); + + A[ 0] = B00 ^ (~B01 & B02); + A[ 1] = B01 ^ (~B02 & B03); + A[ 2] = B02 ^ (~B03 & B04); + A[ 3] = B03 ^ (~B04 & B00); + A[ 4] = B04 ^ (~B00 & B01); + A[ 5] = B05 ^ (~B06 & B07); + A[ 6] = B06 ^ (~B07 & B08); + A[ 7] = B07 ^ (~B08 & B09); + A[ 8] = B08 ^ (~B09 & B05); + A[ 9] = B09 ^ (~B05 & B06); + A[10] = B10 ^ (~B11 & B12); + A[11] = B11 ^ (~B12 & B13); + A[12] = B12 ^ (~B13 & B14); + A[13] = B13 ^ (~B14 & B10); + A[14] = B14 ^ (~B10 & B11); + A[15] = B15 ^ (~B16 & B17); + A[16] = B16 ^ (~B17 & B18); + A[17] = B17 ^ (~B18 & B19); + A[18] = B18 ^ (~B19 & B15); + A[19] = B19 ^ (~B15 & B16); + A[20] = B20 ^ (~B21 & B22); + A[21] = B21 ^ (~B22 & B23); + A[22] = B22 ^ (~B23 & B24); + A[23] = B23 ^ (~B24 & B20); + A[24] = B24 ^ (~B20 & B21); + + A[0] ^= RC[i]; + } + } + +} + +Keccak_1600::Keccak_1600(size_t output_bits) : + output_bits(output_bits), + bitrate(1600 - 2*output_bits), + S(25), + S_pos(0) + { + // We only support the parameters for the SHA-3 proposal + + if(output_bits != 224 && output_bits != 256 && + output_bits != 384 && output_bits != 512) + throw Invalid_Argument("Keccak_1600: Invalid output length " + + to_string(output_bits)); + } + +std::string Keccak_1600::name() const + { + return "Keccak-1600(" + to_string(output_bits) + ")"; + } + +HashFunction* Keccak_1600::clone() const + { + return new Keccak_1600(output_bits); + } + +void Keccak_1600::clear() + { + zeroise(S); + S_pos = 0; + } + +void Keccak_1600::add_data(const byte input[], size_t length) + { + if(length == 0) + return; + + while(length) + { + size_t to_take = std::min(length, bitrate / 8 - S_pos); + + length -= to_take; + + while(to_take && S_pos % 8) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + while(to_take && to_take % 8 == 0) + { + S[S_pos / 8] ^= load_le(input, 0); + S_pos += 8; + input += 8; + to_take -= 8; + } + + while(to_take) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + if(S_pos == bitrate / 8) + { + keccak_f_1600(&S[0]); + S_pos = 0; + } + } + } + +void Keccak_1600::final_result(byte output[]) + { + MemoryVector padding(bitrate / 8 - S_pos); + + padding[0] = 0x01; + padding[padding.size()-1] |= 0x80; + + add_data(padding, padding.size()); + + /* + * We never have to run the permutation again because we only support + * limited output lengths + */ + for(size_t i = 0; i != output_bits/8; ++i) + output[i] = get_byte(7 - (i % 8), S[i/8]); + + clear(); + } + +} +/* +* MD2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/** +* MD2 Compression Function +*/ +void MD2::hash(const byte input[]) + { + static const byte SBOX[256] = { + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, + 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, + 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 0x80, 0x7F, 0x5D, 0x9A, + 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, + 0xAC, 0x56, 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, 0x70, 0x59, + 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, + 0x34, 0x40, 0x7E, 0x0F, 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, + 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, + 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, + 0x9F, 0x11, 0x83, 0x14 }; + + X.copy(16, input, hash_block_size()); + xor_buf(&X[32], &X[0], &X[16], hash_block_size()); + byte T = 0; + + for(size_t i = 0; i != 18; ++i) + { + for(size_t k = 0; k != 48; k += 8) + { + T = X[k ] ^= SBOX[T]; T = X[k+1] ^= SBOX[T]; + T = X[k+2] ^= SBOX[T]; T = X[k+3] ^= SBOX[T]; + T = X[k+4] ^= SBOX[T]; T = X[k+5] ^= SBOX[T]; + T = X[k+6] ^= SBOX[T]; T = X[k+7] ^= SBOX[T]; + } + + T += static_cast(i); + } + + T = checksum[15]; + for(size_t i = 0; i != hash_block_size(); ++i) + T = checksum[i] ^= SBOX[input[i] ^ T]; + } + +/** +* Update the hash +*/ +void MD2::add_data(const byte input[], size_t length) + { + buffer.copy(position, input, length); + + if(position + length >= hash_block_size()) + { + hash(&buffer[0]); + input += (hash_block_size() - position); + length -= (hash_block_size() - position); + while(length >= hash_block_size()) + { + hash(input); + input += hash_block_size(); + length -= hash_block_size(); + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/** +* Finalize a MD2 Hash +*/ +void MD2::final_result(byte output[]) + { + for(size_t i = position; i != hash_block_size(); ++i) + buffer[i] = static_cast(hash_block_size() - position); + + hash(&buffer[0]); + hash(&checksum[0]); + copy_mem(output, &X[0], output_length()); + clear(); + } + +/** +* Clear memory of sensitive data +*/ +void MD2::clear() + { + zeroise(X); + zeroise(checksum); + zeroise(buffer); + position = 0; + } + +} +/* +* MD4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* MD4 FF Function +*/ +inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += (D ^ (B & (C ^ D))) + M; + A = rotate_left(A, S); + } + +/* +* MD4 GG Function +*/ +inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += ((B & C) | (D & (B | C))) + M + 0x5A827999; + A = rotate_left(A, S); + } + +/* +* MD4 HH Function +*/ +inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit M, byte S) + { + A += (B ^ C ^ D) + M + 0x6ED9EBA1; + A = rotate_left(A, S); + } + +} + +/* +* MD4 Compression Function +*/ +void MD4::compress_n(const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + FF(A,B,C,D,M[ 0], 3); FF(D,A,B,C,M[ 1], 7); + FF(C,D,A,B,M[ 2],11); FF(B,C,D,A,M[ 3],19); + FF(A,B,C,D,M[ 4], 3); FF(D,A,B,C,M[ 5], 7); + FF(C,D,A,B,M[ 6],11); FF(B,C,D,A,M[ 7],19); + FF(A,B,C,D,M[ 8], 3); FF(D,A,B,C,M[ 9], 7); + FF(C,D,A,B,M[10],11); FF(B,C,D,A,M[11],19); + FF(A,B,C,D,M[12], 3); FF(D,A,B,C,M[13], 7); + FF(C,D,A,B,M[14],11); FF(B,C,D,A,M[15],19); + + GG(A,B,C,D,M[ 0], 3); GG(D,A,B,C,M[ 4], 5); + GG(C,D,A,B,M[ 8], 9); GG(B,C,D,A,M[12],13); + GG(A,B,C,D,M[ 1], 3); GG(D,A,B,C,M[ 5], 5); + GG(C,D,A,B,M[ 9], 9); GG(B,C,D,A,M[13],13); + GG(A,B,C,D,M[ 2], 3); GG(D,A,B,C,M[ 6], 5); + GG(C,D,A,B,M[10], 9); GG(B,C,D,A,M[14],13); + GG(A,B,C,D,M[ 3], 3); GG(D,A,B,C,M[ 7], 5); + GG(C,D,A,B,M[11], 9); GG(B,C,D,A,M[15],13); + + HH(A,B,C,D,M[ 0], 3); HH(D,A,B,C,M[ 8], 9); + HH(C,D,A,B,M[ 4],11); HH(B,C,D,A,M[12],15); + HH(A,B,C,D,M[ 2], 3); HH(D,A,B,C,M[10], 9); + HH(C,D,A,B,M[ 6],11); HH(B,C,D,A,M[14],15); + HH(A,B,C,D,M[ 1], 3); HH(D,A,B,C,M[ 9], 9); + HH(C,D,A,B,M[ 5],11); HH(B,C,D,A,M[13],15); + HH(A,B,C,D,M[ 3], 3); HH(D,A,B,C,M[11], 9); + HH(C,D,A,B,M[ 7],11); HH(B,C,D,A,M[15],15); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD4::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void MD4::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} +/* +* MD5 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* MD5 FF Function +*/ +inline void FF(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 GG Function +*/ +inline void GG(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 HH Function +*/ +inline void HH(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (B ^ C ^ D) + msg + magic; + A = rotate_left(A, S) + B; + } + +/* +* MD5 II Function +*/ +inline void II(u32bit& A, u32bit B, u32bit C, u32bit D, u32bit msg, + byte S, u32bit magic) + { + A += (C ^ (B | ~D)) + msg + magic; + A = rotate_left(A, S) + B; + } + +} + +/* +* MD5 Compression Function +*/ +void MD5::compress_n(const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + FF(A,B,C,D,M[ 0], 7,0xD76AA478); FF(D,A,B,C,M[ 1],12,0xE8C7B756); + FF(C,D,A,B,M[ 2],17,0x242070DB); FF(B,C,D,A,M[ 3],22,0xC1BDCEEE); + FF(A,B,C,D,M[ 4], 7,0xF57C0FAF); FF(D,A,B,C,M[ 5],12,0x4787C62A); + FF(C,D,A,B,M[ 6],17,0xA8304613); FF(B,C,D,A,M[ 7],22,0xFD469501); + FF(A,B,C,D,M[ 8], 7,0x698098D8); FF(D,A,B,C,M[ 9],12,0x8B44F7AF); + FF(C,D,A,B,M[10],17,0xFFFF5BB1); FF(B,C,D,A,M[11],22,0x895CD7BE); + FF(A,B,C,D,M[12], 7,0x6B901122); FF(D,A,B,C,M[13],12,0xFD987193); + FF(C,D,A,B,M[14],17,0xA679438E); FF(B,C,D,A,M[15],22,0x49B40821); + + GG(A,B,C,D,M[ 1], 5,0xF61E2562); GG(D,A,B,C,M[ 6], 9,0xC040B340); + GG(C,D,A,B,M[11],14,0x265E5A51); GG(B,C,D,A,M[ 0],20,0xE9B6C7AA); + GG(A,B,C,D,M[ 5], 5,0xD62F105D); GG(D,A,B,C,M[10], 9,0x02441453); + GG(C,D,A,B,M[15],14,0xD8A1E681); GG(B,C,D,A,M[ 4],20,0xE7D3FBC8); + GG(A,B,C,D,M[ 9], 5,0x21E1CDE6); GG(D,A,B,C,M[14], 9,0xC33707D6); + GG(C,D,A,B,M[ 3],14,0xF4D50D87); GG(B,C,D,A,M[ 8],20,0x455A14ED); + GG(A,B,C,D,M[13], 5,0xA9E3E905); GG(D,A,B,C,M[ 2], 9,0xFCEFA3F8); + GG(C,D,A,B,M[ 7],14,0x676F02D9); GG(B,C,D,A,M[12],20,0x8D2A4C8A); + + HH(A,B,C,D,M[ 5], 4,0xFFFA3942); HH(D,A,B,C,M[ 8],11,0x8771F681); + HH(C,D,A,B,M[11],16,0x6D9D6122); HH(B,C,D,A,M[14],23,0xFDE5380C); + HH(A,B,C,D,M[ 1], 4,0xA4BEEA44); HH(D,A,B,C,M[ 4],11,0x4BDECFA9); + HH(C,D,A,B,M[ 7],16,0xF6BB4B60); HH(B,C,D,A,M[10],23,0xBEBFBC70); + HH(A,B,C,D,M[13], 4,0x289B7EC6); HH(D,A,B,C,M[ 0],11,0xEAA127FA); + HH(C,D,A,B,M[ 3],16,0xD4EF3085); HH(B,C,D,A,M[ 6],23,0x04881D05); + HH(A,B,C,D,M[ 9], 4,0xD9D4D039); HH(D,A,B,C,M[12],11,0xE6DB99E5); + HH(C,D,A,B,M[15],16,0x1FA27CF8); HH(B,C,D,A,M[ 2],23,0xC4AC5665); + + II(A,B,C,D,M[ 0], 6,0xF4292244); II(D,A,B,C,M[ 7],10,0x432AFF97); + II(C,D,A,B,M[14],15,0xAB9423A7); II(B,C,D,A,M[ 5],21,0xFC93A039); + II(A,B,C,D,M[12], 6,0x655B59C3); II(D,A,B,C,M[ 3],10,0x8F0CCC92); + II(C,D,A,B,M[10],15,0xFFEFF47D); II(B,C,D,A,M[ 1],21,0x85845DD1); + II(A,B,C,D,M[ 8], 6,0x6FA87E4F); II(D,A,B,C,M[15],10,0xFE2CE6E0); + II(C,D,A,B,M[ 6],15,0xA3014314); II(B,C,D,A,M[13],21,0x4E0811A1); + II(A,B,C,D,M[ 4], 6,0xF7537E82); II(D,A,B,C,M[11],10,0xBD3AF235); + II(C,D,A,B,M[ 2],15,0x2AD7D2BB); II(B,C,D,A,M[ 9],21,0xEB86D391); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD5::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void MD5::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} +/* +* Merkle-Damgard Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* MDx_HashFunction Constructor +*/ +MDx_HashFunction::MDx_HashFunction(size_t block_len, + bool byte_end, + bool bit_end, + size_t cnt_size) : + buffer(block_len), + BIG_BYTE_ENDIAN(byte_end), + BIG_BIT_ENDIAN(bit_end), + COUNT_SIZE(cnt_size) + { + count = position = 0; + } + +/* +* Clear memory of sensitive data +*/ +void MDx_HashFunction::clear() + { + zeroise(buffer); + count = position = 0; + } + +/* +* Update the hash +*/ +void MDx_HashFunction::add_data(const byte input[], size_t length) + { + count += length; + + if(position) + { + buffer.copy(position, input, length); + + if(position + length >= buffer.size()) + { + compress_n(&buffer[0], 1); + input += (buffer.size() - position); + length -= (buffer.size() - position); + position = 0; + } + } + + const size_t full_blocks = length / buffer.size(); + const size_t remaining = length % buffer.size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer.copy(position, input + full_blocks * buffer.size(), remaining); + position += remaining; + } + +/* +* Finalize a hash +*/ +void MDx_HashFunction::final_result(byte output[]) + { + buffer[position] = (BIG_BIT_ENDIAN ? 0x80 : 0x01); + for(size_t i = position+1; i != buffer.size(); ++i) + buffer[i] = 0; + + if(position >= buffer.size() - COUNT_SIZE) + { + compress_n(&buffer[0], 1); + zeroise(buffer); + } + + write_count(&buffer[buffer.size() - COUNT_SIZE]); + + compress_n(&buffer[0], 1); + copy_out(output); + clear(); + } + +/* +* Write the count bits to the buffer +*/ +void MDx_HashFunction::write_count(byte out[]) + { + if(COUNT_SIZE < 8) + throw Invalid_State("MDx_HashFunction::write_count: COUNT_SIZE < 8"); + if(COUNT_SIZE >= output_length() || COUNT_SIZE >= hash_block_size()) + throw Invalid_Argument("MDx_HashFunction: COUNT_SIZE is too big"); + + const u64bit bit_count = count * 8; + + if(BIG_BYTE_ENDIAN) + store_be(bit_count, out + COUNT_SIZE - 8); + else + store_le(bit_count, out + COUNT_SIZE - 8); + } + +} +/* +* Parallel +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Update the hash +*/ +void Parallel::add_data(const byte input[], size_t length) + { + for(size_t i = 0; i != hashes.size(); ++i) + hashes[i]->update(input, length); + } + +/* +* Finalize the hash +*/ +void Parallel::final_result(byte hash[]) + { + size_t offset = 0; + for(size_t i = 0; i != hashes.size(); ++i) + { + hashes[i]->final(hash + offset); + offset += hashes[i]->output_length(); + } + } + +/* +* Return output size +*/ +size_t Parallel::output_length() const + { + size_t sum = 0; + for(size_t i = 0; i != hashes.size(); ++i) + sum += hashes[i]->output_length(); + return sum; + } + +/* +* Return the name of this type +*/ +std::string Parallel::name() const + { + std::string hash_names; + for(size_t i = 0; i != hashes.size(); ++i) + { + if(i) + hash_names += ','; + hash_names += hashes[i]->name(); + } + return "Parallel(" + hash_names + ")"; + } + +/* +* Return a clone of this object +*/ +HashFunction* Parallel::clone() const + { + std::vector hash_copies; + for(size_t i = 0; i != hashes.size(); ++i) + hash_copies.push_back(hashes[i]->clone()); + return new Parallel(hash_copies); + } + +/* +* Clear memory of sensitive data +*/ +void Parallel::clear() + { + for(size_t i = 0; i != hashes.size(); ++i) + hashes[i]->clear(); + } + +/* +* Parallel Constructor +*/ +Parallel::Parallel(const std::vector& hash_in) : + hashes(hash_in) + { + } + +/* +* Parallel Destructor +*/ +Parallel::~Parallel() + { + for(size_t i = 0; i != hashes.size(); ++i) + delete hashes[i]; + } + +} +/* +* RIPEMD-128 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace RIPEMD_128_F { + +/* +* RIPEMD-128 F1 Function +*/ +inline void F1(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift) + { + A += (B ^ C ^ D) + msg; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F2 Function +*/ +inline void F2(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F3 Function +*/ +inline void F3(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B | ~C)) + msg + magic; + A = rotate_left(A, shift); + } + +/* +* RIPEMD-128 F4 Function +*/ +inline void F4(u32bit& A, u32bit B, u32bit C, u32bit D, + u32bit msg, u32bit shift, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, shift); + } + +} + +/* +* RIPEMD-128 Compression Function +*/ +void RIPEMD_128::compress_n(const byte input[], size_t blocks) + { + using namespace RIPEMD_128_F; + + const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, + MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0x50A28BE6, + MAGIC6 = 0x5C4DD124, MAGIC7 = 0x6D703EF3; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1, + C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1; + + F1(A1,B1,C1,D1,M[ 0],11 ); F4(A2,B2,C2,D2,M[ 5], 8,MAGIC5); + F1(D1,A1,B1,C1,M[ 1],14 ); F4(D2,A2,B2,C2,M[14], 9,MAGIC5); + F1(C1,D1,A1,B1,M[ 2],15 ); F4(C2,D2,A2,B2,M[ 7], 9,MAGIC5); + F1(B1,C1,D1,A1,M[ 3],12 ); F4(B2,C2,D2,A2,M[ 0],11,MAGIC5); + F1(A1,B1,C1,D1,M[ 4], 5 ); F4(A2,B2,C2,D2,M[ 9],13,MAGIC5); + F1(D1,A1,B1,C1,M[ 5], 8 ); F4(D2,A2,B2,C2,M[ 2],15,MAGIC5); + F1(C1,D1,A1,B1,M[ 6], 7 ); F4(C2,D2,A2,B2,M[11],15,MAGIC5); + F1(B1,C1,D1,A1,M[ 7], 9 ); F4(B2,C2,D2,A2,M[ 4], 5,MAGIC5); + F1(A1,B1,C1,D1,M[ 8],11 ); F4(A2,B2,C2,D2,M[13], 7,MAGIC5); + F1(D1,A1,B1,C1,M[ 9],13 ); F4(D2,A2,B2,C2,M[ 6], 7,MAGIC5); + F1(C1,D1,A1,B1,M[10],14 ); F4(C2,D2,A2,B2,M[15], 8,MAGIC5); + F1(B1,C1,D1,A1,M[11],15 ); F4(B2,C2,D2,A2,M[ 8],11,MAGIC5); + F1(A1,B1,C1,D1,M[12], 6 ); F4(A2,B2,C2,D2,M[ 1],14,MAGIC5); + F1(D1,A1,B1,C1,M[13], 7 ); F4(D2,A2,B2,C2,M[10],14,MAGIC5); + F1(C1,D1,A1,B1,M[14], 9 ); F4(C2,D2,A2,B2,M[ 3],12,MAGIC5); + F1(B1,C1,D1,A1,M[15], 8 ); F4(B2,C2,D2,A2,M[12], 6,MAGIC5); + + F2(A1,B1,C1,D1,M[ 7], 7,MAGIC2); F3(A2,B2,C2,D2,M[ 6], 9,MAGIC6); + F2(D1,A1,B1,C1,M[ 4], 6,MAGIC2); F3(D2,A2,B2,C2,M[11],13,MAGIC6); + F2(C1,D1,A1,B1,M[13], 8,MAGIC2); F3(C2,D2,A2,B2,M[ 3],15,MAGIC6); + F2(B1,C1,D1,A1,M[ 1],13,MAGIC2); F3(B2,C2,D2,A2,M[ 7], 7,MAGIC6); + F2(A1,B1,C1,D1,M[10],11,MAGIC2); F3(A2,B2,C2,D2,M[ 0],12,MAGIC6); + F2(D1,A1,B1,C1,M[ 6], 9,MAGIC2); F3(D2,A2,B2,C2,M[13], 8,MAGIC6); + F2(C1,D1,A1,B1,M[15], 7,MAGIC2); F3(C2,D2,A2,B2,M[ 5], 9,MAGIC6); + F2(B1,C1,D1,A1,M[ 3],15,MAGIC2); F3(B2,C2,D2,A2,M[10],11,MAGIC6); + F2(A1,B1,C1,D1,M[12], 7,MAGIC2); F3(A2,B2,C2,D2,M[14], 7,MAGIC6); + F2(D1,A1,B1,C1,M[ 0],12,MAGIC2); F3(D2,A2,B2,C2,M[15], 7,MAGIC6); + F2(C1,D1,A1,B1,M[ 9],15,MAGIC2); F3(C2,D2,A2,B2,M[ 8],12,MAGIC6); + F2(B1,C1,D1,A1,M[ 5], 9,MAGIC2); F3(B2,C2,D2,A2,M[12], 7,MAGIC6); + F2(A1,B1,C1,D1,M[ 2],11,MAGIC2); F3(A2,B2,C2,D2,M[ 4], 6,MAGIC6); + F2(D1,A1,B1,C1,M[14], 7,MAGIC2); F3(D2,A2,B2,C2,M[ 9],15,MAGIC6); + F2(C1,D1,A1,B1,M[11],13,MAGIC2); F3(C2,D2,A2,B2,M[ 1],13,MAGIC6); + F2(B1,C1,D1,A1,M[ 8],12,MAGIC2); F3(B2,C2,D2,A2,M[ 2],11,MAGIC6); + + F3(A1,B1,C1,D1,M[ 3],11,MAGIC3); F2(A2,B2,C2,D2,M[15], 9,MAGIC7); + F3(D1,A1,B1,C1,M[10],13,MAGIC3); F2(D2,A2,B2,C2,M[ 5], 7,MAGIC7); + F3(C1,D1,A1,B1,M[14], 6,MAGIC3); F2(C2,D2,A2,B2,M[ 1],15,MAGIC7); + F3(B1,C1,D1,A1,M[ 4], 7,MAGIC3); F2(B2,C2,D2,A2,M[ 3],11,MAGIC7); + F3(A1,B1,C1,D1,M[ 9],14,MAGIC3); F2(A2,B2,C2,D2,M[ 7], 8,MAGIC7); + F3(D1,A1,B1,C1,M[15], 9,MAGIC3); F2(D2,A2,B2,C2,M[14], 6,MAGIC7); + F3(C1,D1,A1,B1,M[ 8],13,MAGIC3); F2(C2,D2,A2,B2,M[ 6], 6,MAGIC7); + F3(B1,C1,D1,A1,M[ 1],15,MAGIC3); F2(B2,C2,D2,A2,M[ 9],14,MAGIC7); + F3(A1,B1,C1,D1,M[ 2],14,MAGIC3); F2(A2,B2,C2,D2,M[11],12,MAGIC7); + F3(D1,A1,B1,C1,M[ 7], 8,MAGIC3); F2(D2,A2,B2,C2,M[ 8],13,MAGIC7); + F3(C1,D1,A1,B1,M[ 0],13,MAGIC3); F2(C2,D2,A2,B2,M[12], 5,MAGIC7); + F3(B1,C1,D1,A1,M[ 6], 6,MAGIC3); F2(B2,C2,D2,A2,M[ 2],14,MAGIC7); + F3(A1,B1,C1,D1,M[13], 5,MAGIC3); F2(A2,B2,C2,D2,M[10],13,MAGIC7); + F3(D1,A1,B1,C1,M[11],12,MAGIC3); F2(D2,A2,B2,C2,M[ 0],13,MAGIC7); + F3(C1,D1,A1,B1,M[ 5], 7,MAGIC3); F2(C2,D2,A2,B2,M[ 4], 7,MAGIC7); + F3(B1,C1,D1,A1,M[12], 5,MAGIC3); F2(B2,C2,D2,A2,M[13], 5,MAGIC7); + + F4(A1,B1,C1,D1,M[ 1],11,MAGIC4); F1(A2,B2,C2,D2,M[ 8],15 ); + F4(D1,A1,B1,C1,M[ 9],12,MAGIC4); F1(D2,A2,B2,C2,M[ 6], 5 ); + F4(C1,D1,A1,B1,M[11],14,MAGIC4); F1(C2,D2,A2,B2,M[ 4], 8 ); + F4(B1,C1,D1,A1,M[10],15,MAGIC4); F1(B2,C2,D2,A2,M[ 1],11 ); + F4(A1,B1,C1,D1,M[ 0],14,MAGIC4); F1(A2,B2,C2,D2,M[ 3],14 ); + F4(D1,A1,B1,C1,M[ 8],15,MAGIC4); F1(D2,A2,B2,C2,M[11],14 ); + F4(C1,D1,A1,B1,M[12], 9,MAGIC4); F1(C2,D2,A2,B2,M[15], 6 ); + F4(B1,C1,D1,A1,M[ 4], 8,MAGIC4); F1(B2,C2,D2,A2,M[ 0],14 ); + F4(A1,B1,C1,D1,M[13], 9,MAGIC4); F1(A2,B2,C2,D2,M[ 5], 6 ); + F4(D1,A1,B1,C1,M[ 3],14,MAGIC4); F1(D2,A2,B2,C2,M[12], 9 ); + F4(C1,D1,A1,B1,M[ 7], 5,MAGIC4); F1(C2,D2,A2,B2,M[ 2],12 ); + F4(B1,C1,D1,A1,M[15], 6,MAGIC4); F1(B2,C2,D2,A2,M[13], 9 ); + F4(A1,B1,C1,D1,M[14], 8,MAGIC4); F1(A2,B2,C2,D2,M[ 9],12 ); + F4(D1,A1,B1,C1,M[ 5], 6,MAGIC4); F1(D2,A2,B2,C2,M[ 7], 5 ); + F4(C1,D1,A1,B1,M[ 6], 5,MAGIC4); F1(C2,D2,A2,B2,M[10],15 ); + F4(B1,C1,D1,A1,M[ 2],12,MAGIC4); F1(B2,C2,D2,A2,M[14], 8 ); + + D2 = digest[1] + C1 + D2; + digest[1] = digest[2] + D1 + A2; + digest[2] = digest[3] + A1 + B2; + digest[3] = digest[0] + B1 + C2; + digest[0] = D2; + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void RIPEMD_128::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void RIPEMD_128::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + } + +} +/* +* RIPEMD-160 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* RIPEMD-160 F1 Function +*/ +inline void F1(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift) + { + A += (B ^ C ^ D) + msg; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F2 Function +*/ +inline void F2(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B & (C ^ D))) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F3 Function +*/ +inline void F3(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (D ^ (B | ~C)) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F4 Function +*/ +inline void F4(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (C ^ (D & (B ^ C))) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +/* +* RIPEMD-160 F5 Function +*/ +inline void F5(u32bit& A, u32bit B, u32bit& C, u32bit D, u32bit E, + u32bit msg, u32bit shift, u32bit magic) + { + A += (B ^ (C | ~D)) + msg + magic; + A = rotate_left(A, shift) + E; + C = rotate_left(C, 10); + } + +} + +/* +* RIPEMD-160 Compression Function +*/ +void RIPEMD_160::compress_n(const byte input[], size_t blocks) + { + const u32bit MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, + MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E, + MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124, + MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&M[0], input, M.size()); + + u32bit A1 = digest[0], A2 = A1, B1 = digest[1], B2 = B1, + C1 = digest[2], C2 = C1, D1 = digest[3], D2 = D1, + E1 = digest[4], E2 = E1; + + F1(A1,B1,C1,D1,E1,M[ 0],11 ); F5(A2,B2,C2,D2,E2,M[ 5], 8,MAGIC6); + F1(E1,A1,B1,C1,D1,M[ 1],14 ); F5(E2,A2,B2,C2,D2,M[14], 9,MAGIC6); + F1(D1,E1,A1,B1,C1,M[ 2],15 ); F5(D2,E2,A2,B2,C2,M[ 7], 9,MAGIC6); + F1(C1,D1,E1,A1,B1,M[ 3],12 ); F5(C2,D2,E2,A2,B2,M[ 0],11,MAGIC6); + F1(B1,C1,D1,E1,A1,M[ 4], 5 ); F5(B2,C2,D2,E2,A2,M[ 9],13,MAGIC6); + F1(A1,B1,C1,D1,E1,M[ 5], 8 ); F5(A2,B2,C2,D2,E2,M[ 2],15,MAGIC6); + F1(E1,A1,B1,C1,D1,M[ 6], 7 ); F5(E2,A2,B2,C2,D2,M[11],15,MAGIC6); + F1(D1,E1,A1,B1,C1,M[ 7], 9 ); F5(D2,E2,A2,B2,C2,M[ 4], 5,MAGIC6); + F1(C1,D1,E1,A1,B1,M[ 8],11 ); F5(C2,D2,E2,A2,B2,M[13], 7,MAGIC6); + F1(B1,C1,D1,E1,A1,M[ 9],13 ); F5(B2,C2,D2,E2,A2,M[ 6], 7,MAGIC6); + F1(A1,B1,C1,D1,E1,M[10],14 ); F5(A2,B2,C2,D2,E2,M[15], 8,MAGIC6); + F1(E1,A1,B1,C1,D1,M[11],15 ); F5(E2,A2,B2,C2,D2,M[ 8],11,MAGIC6); + F1(D1,E1,A1,B1,C1,M[12], 6 ); F5(D2,E2,A2,B2,C2,M[ 1],14,MAGIC6); + F1(C1,D1,E1,A1,B1,M[13], 7 ); F5(C2,D2,E2,A2,B2,M[10],14,MAGIC6); + F1(B1,C1,D1,E1,A1,M[14], 9 ); F5(B2,C2,D2,E2,A2,M[ 3],12,MAGIC6); + F1(A1,B1,C1,D1,E1,M[15], 8 ); F5(A2,B2,C2,D2,E2,M[12], 6,MAGIC6); + + F2(E1,A1,B1,C1,D1,M[ 7], 7,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 6], 9,MAGIC7); + F2(D1,E1,A1,B1,C1,M[ 4], 6,MAGIC2); F4(D2,E2,A2,B2,C2,M[11],13,MAGIC7); + F2(C1,D1,E1,A1,B1,M[13], 8,MAGIC2); F4(C2,D2,E2,A2,B2,M[ 3],15,MAGIC7); + F2(B1,C1,D1,E1,A1,M[ 1],13,MAGIC2); F4(B2,C2,D2,E2,A2,M[ 7], 7,MAGIC7); + F2(A1,B1,C1,D1,E1,M[10],11,MAGIC2); F4(A2,B2,C2,D2,E2,M[ 0],12,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 6], 9,MAGIC2); F4(E2,A2,B2,C2,D2,M[13], 8,MAGIC7); + F2(D1,E1,A1,B1,C1,M[15], 7,MAGIC2); F4(D2,E2,A2,B2,C2,M[ 5], 9,MAGIC7); + F2(C1,D1,E1,A1,B1,M[ 3],15,MAGIC2); F4(C2,D2,E2,A2,B2,M[10],11,MAGIC7); + F2(B1,C1,D1,E1,A1,M[12], 7,MAGIC2); F4(B2,C2,D2,E2,A2,M[14], 7,MAGIC7); + F2(A1,B1,C1,D1,E1,M[ 0],12,MAGIC2); F4(A2,B2,C2,D2,E2,M[15], 7,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 9],15,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 8],12,MAGIC7); + F2(D1,E1,A1,B1,C1,M[ 5], 9,MAGIC2); F4(D2,E2,A2,B2,C2,M[12], 7,MAGIC7); + F2(C1,D1,E1,A1,B1,M[ 2],11,MAGIC2); F4(C2,D2,E2,A2,B2,M[ 4], 6,MAGIC7); + F2(B1,C1,D1,E1,A1,M[14], 7,MAGIC2); F4(B2,C2,D2,E2,A2,M[ 9],15,MAGIC7); + F2(A1,B1,C1,D1,E1,M[11],13,MAGIC2); F4(A2,B2,C2,D2,E2,M[ 1],13,MAGIC7); + F2(E1,A1,B1,C1,D1,M[ 8],12,MAGIC2); F4(E2,A2,B2,C2,D2,M[ 2],11,MAGIC7); + + F3(D1,E1,A1,B1,C1,M[ 3],11,MAGIC3); F3(D2,E2,A2,B2,C2,M[15], 9,MAGIC8); + F3(C1,D1,E1,A1,B1,M[10],13,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 5], 7,MAGIC8); + F3(B1,C1,D1,E1,A1,M[14], 6,MAGIC3); F3(B2,C2,D2,E2,A2,M[ 1],15,MAGIC8); + F3(A1,B1,C1,D1,E1,M[ 4], 7,MAGIC3); F3(A2,B2,C2,D2,E2,M[ 3],11,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 9],14,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 7], 8,MAGIC8); + F3(D1,E1,A1,B1,C1,M[15], 9,MAGIC3); F3(D2,E2,A2,B2,C2,M[14], 6,MAGIC8); + F3(C1,D1,E1,A1,B1,M[ 8],13,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 6], 6,MAGIC8); + F3(B1,C1,D1,E1,A1,M[ 1],15,MAGIC3); F3(B2,C2,D2,E2,A2,M[ 9],14,MAGIC8); + F3(A1,B1,C1,D1,E1,M[ 2],14,MAGIC3); F3(A2,B2,C2,D2,E2,M[11],12,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 7], 8,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 8],13,MAGIC8); + F3(D1,E1,A1,B1,C1,M[ 0],13,MAGIC3); F3(D2,E2,A2,B2,C2,M[12], 5,MAGIC8); + F3(C1,D1,E1,A1,B1,M[ 6], 6,MAGIC3); F3(C2,D2,E2,A2,B2,M[ 2],14,MAGIC8); + F3(B1,C1,D1,E1,A1,M[13], 5,MAGIC3); F3(B2,C2,D2,E2,A2,M[10],13,MAGIC8); + F3(A1,B1,C1,D1,E1,M[11],12,MAGIC3); F3(A2,B2,C2,D2,E2,M[ 0],13,MAGIC8); + F3(E1,A1,B1,C1,D1,M[ 5], 7,MAGIC3); F3(E2,A2,B2,C2,D2,M[ 4], 7,MAGIC8); + F3(D1,E1,A1,B1,C1,M[12], 5,MAGIC3); F3(D2,E2,A2,B2,C2,M[13], 5,MAGIC8); + + F4(C1,D1,E1,A1,B1,M[ 1],11,MAGIC4); F2(C2,D2,E2,A2,B2,M[ 8],15,MAGIC9); + F4(B1,C1,D1,E1,A1,M[ 9],12,MAGIC4); F2(B2,C2,D2,E2,A2,M[ 6], 5,MAGIC9); + F4(A1,B1,C1,D1,E1,M[11],14,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 4], 8,MAGIC9); + F4(E1,A1,B1,C1,D1,M[10],15,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 1],11,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 0],14,MAGIC4); F2(D2,E2,A2,B2,C2,M[ 3],14,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 8],15,MAGIC4); F2(C2,D2,E2,A2,B2,M[11],14,MAGIC9); + F4(B1,C1,D1,E1,A1,M[12], 9,MAGIC4); F2(B2,C2,D2,E2,A2,M[15], 6,MAGIC9); + F4(A1,B1,C1,D1,E1,M[ 4], 8,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 0],14,MAGIC9); + F4(E1,A1,B1,C1,D1,M[13], 9,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 5], 6,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 3],14,MAGIC4); F2(D2,E2,A2,B2,C2,M[12], 9,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 7], 5,MAGIC4); F2(C2,D2,E2,A2,B2,M[ 2],12,MAGIC9); + F4(B1,C1,D1,E1,A1,M[15], 6,MAGIC4); F2(B2,C2,D2,E2,A2,M[13], 9,MAGIC9); + F4(A1,B1,C1,D1,E1,M[14], 8,MAGIC4); F2(A2,B2,C2,D2,E2,M[ 9],12,MAGIC9); + F4(E1,A1,B1,C1,D1,M[ 5], 6,MAGIC4); F2(E2,A2,B2,C2,D2,M[ 7], 5,MAGIC9); + F4(D1,E1,A1,B1,C1,M[ 6], 5,MAGIC4); F2(D2,E2,A2,B2,C2,M[10],15,MAGIC9); + F4(C1,D1,E1,A1,B1,M[ 2],12,MAGIC4); F2(C2,D2,E2,A2,B2,M[14], 8,MAGIC9); + + F5(B1,C1,D1,E1,A1,M[ 4], 9,MAGIC5); F1(B2,C2,D2,E2,A2,M[12], 8 ); + F5(A1,B1,C1,D1,E1,M[ 0],15,MAGIC5); F1(A2,B2,C2,D2,E2,M[15], 5 ); + F5(E1,A1,B1,C1,D1,M[ 5], 5,MAGIC5); F1(E2,A2,B2,C2,D2,M[10],12 ); + F5(D1,E1,A1,B1,C1,M[ 9],11,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 4], 9 ); + F5(C1,D1,E1,A1,B1,M[ 7], 6,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 1],12 ); + F5(B1,C1,D1,E1,A1,M[12], 8,MAGIC5); F1(B2,C2,D2,E2,A2,M[ 5], 5 ); + F5(A1,B1,C1,D1,E1,M[ 2],13,MAGIC5); F1(A2,B2,C2,D2,E2,M[ 8],14 ); + F5(E1,A1,B1,C1,D1,M[10],12,MAGIC5); F1(E2,A2,B2,C2,D2,M[ 7], 6 ); + F5(D1,E1,A1,B1,C1,M[14], 5,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 6], 8 ); + F5(C1,D1,E1,A1,B1,M[ 1],12,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 2],13 ); + F5(B1,C1,D1,E1,A1,M[ 3],13,MAGIC5); F1(B2,C2,D2,E2,A2,M[13], 6 ); + F5(A1,B1,C1,D1,E1,M[ 8],14,MAGIC5); F1(A2,B2,C2,D2,E2,M[14], 5 ); + F5(E1,A1,B1,C1,D1,M[11],11,MAGIC5); F1(E2,A2,B2,C2,D2,M[ 0],15 ); + F5(D1,E1,A1,B1,C1,M[ 6], 8,MAGIC5); F1(D2,E2,A2,B2,C2,M[ 3],13 ); + F5(C1,D1,E1,A1,B1,M[15], 5,MAGIC5); F1(C2,D2,E2,A2,B2,M[ 9],11 ); + F5(B1,C1,D1,E1,A1,M[13], 6,MAGIC5); F1(B2,C2,D2,E2,A2,M[11],11 ); + + C1 = digest[1] + C1 + D2; + digest[1] = digest[2] + D1 + E2; + digest[2] = digest[3] + E1 + A2; + digest[3] = digest[4] + A1 + B2; + digest[4] = digest[0] + B1 + C2; + digest[0] = C1; + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void RIPEMD_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_le(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void RIPEMD_160::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} +/* +* SHA-160 +* (C) 1999-2008,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace SHA1_F { + +namespace { + +/* +* SHA-160 F1 Function +*/ +inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) + { + E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotate_left(A, 5); + B = rotate_left(B, 30); + } + +} + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160::compress_n(const byte input[], size_t blocks) + { + using namespace SHA1_F; + + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4]; + + for(size_t i = 0; i != blocks; ++i) + { + load_be(&W[0], input, 16); + + for(size_t j = 16; j != 80; j += 8) + { + W[j ] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1); + W[j+1] = rotate_left((W[j-2] ^ W[j-7] ^ W[j-13] ^ W[j-15]), 1); + W[j+2] = rotate_left((W[j-1] ^ W[j-6] ^ W[j-12] ^ W[j-14]), 1); + W[j+3] = rotate_left((W[j ] ^ W[j-5] ^ W[j-11] ^ W[j-13]), 1); + W[j+4] = rotate_left((W[j+1] ^ W[j-4] ^ W[j-10] ^ W[j-12]), 1); + W[j+5] = rotate_left((W[j+2] ^ W[j-3] ^ W[j- 9] ^ W[j-11]), 1); + W[j+6] = rotate_left((W[j+3] ^ W[j-2] ^ W[j- 8] ^ W[j-10]), 1); + W[j+7] = rotate_left((W[j+4] ^ W[j-1] ^ W[j- 7] ^ W[j- 9]), 1); + } + + F1(A, B, C, D, E, W[ 0]); F1(E, A, B, C, D, W[ 1]); + F1(D, E, A, B, C, W[ 2]); F1(C, D, E, A, B, W[ 3]); + F1(B, C, D, E, A, W[ 4]); F1(A, B, C, D, E, W[ 5]); + F1(E, A, B, C, D, W[ 6]); F1(D, E, A, B, C, W[ 7]); + F1(C, D, E, A, B, W[ 8]); F1(B, C, D, E, A, W[ 9]); + F1(A, B, C, D, E, W[10]); F1(E, A, B, C, D, W[11]); + F1(D, E, A, B, C, W[12]); F1(C, D, E, A, B, W[13]); + F1(B, C, D, E, A, W[14]); F1(A, B, C, D, E, W[15]); + F1(E, A, B, C, D, W[16]); F1(D, E, A, B, C, W[17]); + F1(C, D, E, A, B, W[18]); F1(B, C, D, E, A, W[19]); + + F2(A, B, C, D, E, W[20]); F2(E, A, B, C, D, W[21]); + F2(D, E, A, B, C, W[22]); F2(C, D, E, A, B, W[23]); + F2(B, C, D, E, A, W[24]); F2(A, B, C, D, E, W[25]); + F2(E, A, B, C, D, W[26]); F2(D, E, A, B, C, W[27]); + F2(C, D, E, A, B, W[28]); F2(B, C, D, E, A, W[29]); + F2(A, B, C, D, E, W[30]); F2(E, A, B, C, D, W[31]); + F2(D, E, A, B, C, W[32]); F2(C, D, E, A, B, W[33]); + F2(B, C, D, E, A, W[34]); F2(A, B, C, D, E, W[35]); + F2(E, A, B, C, D, W[36]); F2(D, E, A, B, C, W[37]); + F2(C, D, E, A, B, W[38]); F2(B, C, D, E, A, W[39]); + + F3(A, B, C, D, E, W[40]); F3(E, A, B, C, D, W[41]); + F3(D, E, A, B, C, W[42]); F3(C, D, E, A, B, W[43]); + F3(B, C, D, E, A, W[44]); F3(A, B, C, D, E, W[45]); + F3(E, A, B, C, D, W[46]); F3(D, E, A, B, C, W[47]); + F3(C, D, E, A, B, W[48]); F3(B, C, D, E, A, W[49]); + F3(A, B, C, D, E, W[50]); F3(E, A, B, C, D, W[51]); + F3(D, E, A, B, C, W[52]); F3(C, D, E, A, B, W[53]); + F3(B, C, D, E, A, W[54]); F3(A, B, C, D, E, W[55]); + F3(E, A, B, C, D, W[56]); F3(D, E, A, B, C, W[57]); + F3(C, D, E, A, B, W[58]); F3(B, C, D, E, A, W[59]); + + F4(A, B, C, D, E, W[60]); F4(E, A, B, C, D, W[61]); + F4(D, E, A, B, C, W[62]); F4(C, D, E, A, B, W[63]); + F4(B, C, D, E, A, W[64]); F4(A, B, C, D, E, W[65]); + F4(E, A, B, C, D, W[66]); F4(D, E, A, B, C, W[67]); + F4(C, D, E, A, B, W[68]); F4(B, C, D, E, A, W[69]); + F4(A, B, C, D, E, W[70]); F4(E, A, B, C, D, W[71]); + F4(D, E, A, B, C, W[72]); F4(C, D, E, A, B, W[73]); + F4(B, C, D, E, A, W[74]); F4(A, B, C, D, E, W[75]); + F4(E, A, B, C, D, W[76]); F4(D, E, A, B, C, W[77]); + F4(C, D, E, A, B, W[78]); F4(B, C, D, E, A, W[79]); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void SHA_160::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_160::clear() + { + MDx_HashFunction::clear(); + zeroise(W); + digest[0] = 0x67452301; + digest[1] = 0xEFCDAB89; + digest[2] = 0x98BADCFE; + digest[3] = 0x10325476; + digest[4] = 0xC3D2E1F0; + } + +} +/* +* SHA-{224,256} +* (C) 1999-2010 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +namespace SHA2_32 { + +/* +* SHA-256 Rho Function +*/ +inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ + rotate_right(X, rot3)); + } + +/* +* SHA-256 Sigma Function +*/ +inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift)); + } + +/* +* SHA-256 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 17, 19, 10) + M3 + sigma(M4, 7, 18, 3); \ + } while(0); + +/* +* SHA-224 / SHA-256 compression function +*/ +void compress(MemoryRegion& digest, + const byte input[], size_t blocks) + { + u32bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit W00 = load_be(input, 0); + u32bit W01 = load_be(input, 1); + u32bit W02 = load_be(input, 2); + u32bit W03 = load_be(input, 3); + u32bit W04 = load_be(input, 4); + u32bit W05 = load_be(input, 5); + u32bit W06 = load_be(input, 6); + u32bit W07 = load_be(input, 7); + u32bit W08 = load_be(input, 8); + u32bit W09 = load_be(input, 9); + u32bit W10 = load_be(input, 10); + u32bit W11 = load_be(input, 11); + u32bit W12 = load_be(input, 12); + u32bit W13 = load_be(input, 13); + u32bit W14 = load_be(input, 14); + u32bit W15 = load_be(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +} + +} + +/* +* SHA-224 compression function +*/ +void SHA_224::compress_n(const byte input[], size_t blocks) + { + SHA2_32::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_224::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_224::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0xC1059ED8; + digest[1] = 0x367CD507; + digest[2] = 0x3070DD17; + digest[3] = 0xF70E5939; + digest[4] = 0xFFC00B31; + digest[5] = 0x68581511; + digest[6] = 0x64F98FA7; + digest[7] = 0xBEFA4FA4; + } + +/* +* SHA-256 compression function +*/ +void SHA_256::compress_n(const byte input[], size_t blocks) + { + SHA2_32::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_256::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 4) + store_be(digest[i/4], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_256::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0x6A09E667; + digest[1] = 0xBB67AE85; + digest[2] = 0x3C6EF372; + digest[3] = 0xA54FF53A; + digest[4] = 0x510E527F; + digest[5] = 0x9B05688C; + digest[6] = 0x1F83D9AB; + digest[7] = 0x5BE0CD19; + } + +} +/* +* SHA-{384,512} +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +namespace SHA2_64 { + +/* +* SHA-{384,512} Rho Function +*/ +inline u64bit rho(u64bit X, u32bit rot1, u32bit rot2, u32bit rot3) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ + rotate_right(X, rot3)); + } + +/* +* SHA-{384,512} Sigma Function +*/ +inline u64bit sigma(u64bit X, u32bit rot1, u32bit rot2, u32bit shift) + { + return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift)); + } + +/* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 14, 18, 41) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 28, 34, 39) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 19, 61, 6) + M3 + sigma(M4, 1, 8, 7); \ + } while(0); + +/* +* SHA-{384,512} Compression Function +*/ +void compress(MemoryRegion& digest, + const byte input[], size_t blocks) + { + u64bit A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + u64bit W00 = load_be(input, 0); + u64bit W01 = load_be(input, 1); + u64bit W02 = load_be(input, 2); + u64bit W03 = load_be(input, 3); + u64bit W04 = load_be(input, 4); + u64bit W05 = load_be(input, 5); + u64bit W06 = load_be(input, 6); + u64bit W07 = load_be(input, 7); + u64bit W08 = load_be(input, 8); + u64bit W09 = load_be(input, 9); + u64bit W10 = load_be(input, 10); + u64bit W11 = load_be(input, 11); + u64bit W12 = load_be(input, 12); + u64bit W13 = load_be(input, 13); + u64bit W14 = load_be(input, 14); + u64bit W15 = load_be(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CDULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2FULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBCULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9BULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBEULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28CULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896FULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235ULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5ULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4ULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFABULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213FULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826FULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFCULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AEDULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DFULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DEULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6ULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353BULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791ULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202AULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99ULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACBULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373ULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3ULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FCULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72ULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439ECULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915ULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532BULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619CULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1EULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178ULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBAULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6ULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAEULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471BULL); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84ULL); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493ULL); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBCULL); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4CULL); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6ULL); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2AULL); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAECULL); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817ULL); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 128; + } + } + +} + +} + +/* +* SHA-384 compression function +*/ +void SHA_384::compress_n(const byte input[], size_t blocks) + { + SHA2_64::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_384::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_384::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0xCBBB9D5DC1059ED8ULL; + digest[1] = 0x629A292A367CD507ULL; + digest[2] = 0x9159015A3070DD17ULL; + digest[3] = 0x152FECD8F70E5939ULL; + digest[4] = 0x67332667FFC00B31ULL; + digest[5] = 0x8EB44A8768581511ULL; + digest[6] = 0xDB0C2E0D64F98FA7ULL; + digest[7] = 0x47B5481DBEFA4FA4ULL; + } + +/* +* SHA-512 compression function +*/ +void SHA_512::compress_n(const byte input[], size_t blocks) + { + SHA2_64::compress(digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_512::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_512::clear() + { + MDx_HashFunction::clear(); + digest[0] = 0x6A09E667F3BCC908ULL; + digest[1] = 0xBB67AE8584CAA73BULL; + digest[2] = 0x3C6EF372FE94F82BULL; + digest[3] = 0xA54FF53A5F1D36F1ULL; + digest[4] = 0x510E527FADE682D1ULL; + digest[5] = 0x9B05688C2B3E6C1FULL; + digest[6] = 0x1F83D9ABFB41BD6BULL; + digest[7] = 0x5BE0CD19137E2179ULL; + } + +} +/* +* The Skein-512 hash function +* (C) 2009-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +enum type_code { + SKEIN_KEY = 0, + SKEIN_CONFIG = 4, + SKEIN_PERSONALIZATION = 8, + SKEIN_PUBLIC_KEY = 12, + SKEIN_KEY_IDENTIFIER = 16, + SKEIN_NONCE = 20, + SKEIN_MSG = 48, + SKEIN_OUTPUT = 63 +}; + +void ubi_512(MemoryRegion& H, + MemoryRegion& T, + const byte msg[], size_t msg_len) + { + do + { + const size_t to_proc = std::min(msg_len, 64); + T[0] += to_proc; + + u64bit M[8] = { 0 }; + + load_le(M, msg, to_proc / 8); + + if(to_proc % 8) + { + for(size_t j = 0; j != to_proc % 8; ++j) + M[to_proc/8] |= static_cast(msg[8*(to_proc/8)+j]) << (8*j); + } + + H[8] = H[0] ^ H[1] ^ H[2] ^ H[3] ^ + H[4] ^ H[5] ^ H[6] ^ H[7] ^ 0x1BD11BDAA9FC1A22ULL; + + T[2] = T[0] ^ T[1]; + + u64bit X0 = M[0] + H[0]; + u64bit X1 = M[1] + H[1]; + u64bit X2 = M[2] + H[2]; + u64bit X3 = M[3] + H[3]; + u64bit X4 = M[4] + H[4]; + u64bit X5 = M[5] + H[5] + T[0]; + u64bit X6 = M[6] + H[6] + T[1]; + u64bit X7 = M[7] + H[7]; + +#define THREEFISH_ROUND(I1,I2,I3,I4,I5,I6,I7,I8,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X##I1 += X##I2; X##I2 = rotate_left(X##I2, ROT1) ^ X##I1; \ + X##I3 += X##I4; X##I4 = rotate_left(X##I4, ROT2) ^ X##I3; \ + X##I5 += X##I6; X##I6 = rotate_left(X##I6, ROT3) ^ X##I5; \ + X##I7 += X##I8; X##I8 = rotate_left(X##I8, ROT4) ^ X##I7; \ + } while(0); + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 += H[(r ) % 9]; \ + X1 += H[(r+1) % 9]; \ + X2 += H[(r+2) % 9]; \ + X3 += H[(r+3) % 9]; \ + X4 += H[(r+4) % 9]; \ + X5 += H[(r+5) % 9] + T[(r ) % 3]; \ + X6 += H[(r+6) % 9] + T[(r+1) % 3]; \ + X7 += H[(r+7) % 9] + (r); \ + } while(0); + +#define THREEFISH_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(0,1,2,3,4,5,6,7, 46,36,19,37); \ + THREEFISH_ROUND(2,1,4,7,6,5,0,3, 33,27,14,42); \ + THREEFISH_ROUND(4,1,6,3,0,5,2,7, 17,49,36,39); \ + THREEFISH_ROUND(6,1,0,7,2,5,4,3, 44, 9,54,56); \ + \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(0,1,2,3,4,5,6,7, 39,30,34,24); \ + THREEFISH_ROUND(2,1,4,7,6,5,0,3, 13,50,10,17); \ + THREEFISH_ROUND(4,1,6,3,0,5,2,7, 25,29,39,43); \ + THREEFISH_ROUND(6,1,0,7,2,5,4,3, 8,35,56,22); \ + \ + THREEFISH_INJECT_KEY(R2); \ + } while(0); + + THREEFISH_8_ROUNDS(1,2); + THREEFISH_8_ROUNDS(3,4); + THREEFISH_8_ROUNDS(5,6); + THREEFISH_8_ROUNDS(7,8); + THREEFISH_8_ROUNDS(9,10); + THREEFISH_8_ROUNDS(11,12); + THREEFISH_8_ROUNDS(13,14); + THREEFISH_8_ROUNDS(15,16); + THREEFISH_8_ROUNDS(17,18); + + // message feed forward + H[0] = X0 ^ M[0]; + H[1] = X1 ^ M[1]; + H[2] = X2 ^ M[2]; + H[3] = X3 ^ M[3]; + H[4] = X4 ^ M[4]; + H[5] = X5 ^ M[5]; + H[6] = X6 ^ M[6]; + H[7] = X7 ^ M[7]; + + // clear first flag if set + T[1] &= ~(static_cast(1) << 62); + + msg_len -= to_proc; + msg += to_proc; + } while(msg_len); + } + +void reset_tweak(MemoryRegion& T, + type_code type, bool final) + { + T[0] = 0; + + T[1] = (static_cast(type) << 56) | + (static_cast(1) << 62) | + (static_cast(final) << 63); + } + +void initial_block(MemoryRegion& H, + MemoryRegion& T, + size_t output_bits, + const std::string& personalization) + { + zeroise(H); + + // ASCII("SHA3") followed by version (0x0001) code + byte config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 }; + store_le(u32bit(output_bits), config_str + 8); + + reset_tweak(T, SKEIN_CONFIG, true); + ubi_512(H, T, config_str, sizeof(config_str)); + + if(personalization != "") + { + /* + This is a limitation of this implementation, and not of the + algorithm specification. Could be fixed relatively easily, but + doesn't seem worth the trouble. + */ + if(personalization.length() > 64) + throw Invalid_Argument("Skein personalization must be <= 64 bytes"); + + const byte* bits = reinterpret_cast(personalization.data()); + + reset_tweak(T, SKEIN_PERSONALIZATION, true); + ubi_512(H, T, bits, personalization.length()); + } + + reset_tweak(T, SKEIN_MSG, false); + } + +} + +Skein_512::Skein_512(size_t arg_output_bits, + const std::string& arg_personalization) : + personalization(arg_personalization), + output_bits(arg_output_bits), + H(9), T(3), buffer(64), buf_pos(0) + { + if(output_bits == 0 || output_bits % 8 != 0 || output_bits > 64*1024) + throw Invalid_Argument("Bad output bits size for Skein-512"); + + initial_block(H, T, output_bits, personalization); + } + +std::string Skein_512::name() const + { + if(personalization != "") + return "Skein-512(" + to_string(output_bits) + "," + personalization + ")"; + return "Skein-512(" + to_string(output_bits) + ")"; + } + +HashFunction* Skein_512::clone() const + { + return new Skein_512(output_bits, personalization); + } + +void Skein_512::clear() + { + zeroise(H); + zeroise(T); + zeroise(buffer); + buf_pos = 0; + } + +void Skein_512::add_data(const byte input[], size_t length) + { + if(length == 0) + return; + + if(buf_pos) + { + buffer.copy(buf_pos, input, length); + if(buf_pos + length > 64) + { + ubi_512(H, T, &buffer[0], buffer.size()); + + input += (64 - buf_pos); + length -= (64 - buf_pos); + buf_pos = 0; + } + } + + const size_t full_blocks = (length - 1) / 64; + + if(full_blocks) + ubi_512(H, T, input, 64*full_blocks); + + length -= full_blocks * 64; + + buffer.copy(buf_pos, input + full_blocks * 64, length); + buf_pos += length; + } + +void Skein_512::final_result(byte out[]) + { + T[1] |= (static_cast(1) << 63); // final block flag + + for(size_t i = buf_pos; i != buffer.size(); ++i) + buffer[i] = 0; + + ubi_512(H, T, &buffer[0], buf_pos); + + byte counter[8] = { 0 }; + + size_t out_bytes = output_bits / 8; + + SecureVector H_out(9); + + while(out_bytes) + { + const size_t to_proc = std::min(out_bytes, 64); + + H_out.copy(&H[0], 8); + + reset_tweak(T, SKEIN_OUTPUT, true); + ubi_512(H_out, T, counter, sizeof(counter)); + + for(size_t i = 0; i != to_proc; ++i) + out[i] = get_byte(7-i%8, H_out[i/8]); + + out_bytes -= to_proc; + out += to_proc; + + for(size_t i = 0; i != sizeof(counter); ++i) + if(++counter[i]) + break; + } + + buf_pos = 0; + initial_block(H, T, output_bits, personalization); + } + +} +/* +* S-Box Tables for Tiger +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u64bit Tiger::SBOX1[256] = { + 0x02AAB17CF7E90C5EULL, 0xAC424B03E243A8ECULL, 0x72CD5BE30DD5FCD3ULL, + 0x6D019B93F6F97F3AULL, 0xCD9978FFD21F9193ULL, 0x7573A1C9708029E2ULL, + 0xB164326B922A83C3ULL, 0x46883EEE04915870ULL, 0xEAACE3057103ECE6ULL, + 0xC54169B808A3535CULL, 0x4CE754918DDEC47CULL, 0x0AA2F4DFDC0DF40CULL, + 0x10B76F18A74DBEFAULL, 0xC6CCB6235AD1AB6AULL, 0x13726121572FE2FFULL, + 0x1A488C6F199D921EULL, 0x4BC9F9F4DA0007CAULL, 0x26F5E6F6E85241C7ULL, + 0x859079DBEA5947B6ULL, 0x4F1885C5C99E8C92ULL, 0xD78E761EA96F864BULL, + 0x8E36428C52B5C17DULL, 0x69CF6827373063C1ULL, 0xB607C93D9BB4C56EULL, + 0x7D820E760E76B5EAULL, 0x645C9CC6F07FDC42ULL, 0xBF38A078243342E0ULL, + 0x5F6B343C9D2E7D04ULL, 0xF2C28AEB600B0EC6ULL, 0x6C0ED85F7254BCACULL, + 0x71592281A4DB4FE5ULL, 0x1967FA69CE0FED9FULL, 0xFD5293F8B96545DBULL, + 0xC879E9D7F2A7600BULL, 0x860248920193194EULL, 0xA4F9533B2D9CC0B3ULL, + 0x9053836C15957613ULL, 0xDB6DCF8AFC357BF1ULL, 0x18BEEA7A7A370F57ULL, + 0x037117CA50B99066ULL, 0x6AB30A9774424A35ULL, 0xF4E92F02E325249BULL, + 0x7739DB07061CCAE1ULL, 0xD8F3B49CECA42A05ULL, 0xBD56BE3F51382F73ULL, + 0x45FAED5843B0BB28ULL, 0x1C813D5C11BF1F83ULL, 0x8AF0E4B6D75FA169ULL, + 0x33EE18A487AD9999ULL, 0x3C26E8EAB1C94410ULL, 0xB510102BC0A822F9ULL, + 0x141EEF310CE6123BULL, 0xFC65B90059DDB154ULL, 0xE0158640C5E0E607ULL, + 0x884E079826C3A3CFULL, 0x930D0D9523C535FDULL, 0x35638D754E9A2B00ULL, + 0x4085FCCF40469DD5ULL, 0xC4B17AD28BE23A4CULL, 0xCAB2F0FC6A3E6A2EULL, + 0x2860971A6B943FCDULL, 0x3DDE6EE212E30446ULL, 0x6222F32AE01765AEULL, + 0x5D550BB5478308FEULL, 0xA9EFA98DA0EDA22AULL, 0xC351A71686C40DA7ULL, + 0x1105586D9C867C84ULL, 0xDCFFEE85FDA22853ULL, 0xCCFBD0262C5EEF76ULL, + 0xBAF294CB8990D201ULL, 0xE69464F52AFAD975ULL, 0x94B013AFDF133E14ULL, + 0x06A7D1A32823C958ULL, 0x6F95FE5130F61119ULL, 0xD92AB34E462C06C0ULL, + 0xED7BDE33887C71D2ULL, 0x79746D6E6518393EULL, 0x5BA419385D713329ULL, + 0x7C1BA6B948A97564ULL, 0x31987C197BFDAC67ULL, 0xDE6C23C44B053D02ULL, + 0x581C49FED002D64DULL, 0xDD474D6338261571ULL, 0xAA4546C3E473D062ULL, + 0x928FCE349455F860ULL, 0x48161BBACAAB94D9ULL, 0x63912430770E6F68ULL, + 0x6EC8A5E602C6641CULL, 0x87282515337DDD2BULL, 0x2CDA6B42034B701BULL, + 0xB03D37C181CB096DULL, 0xE108438266C71C6FULL, 0x2B3180C7EB51B255ULL, + 0xDF92B82F96C08BBCULL, 0x5C68C8C0A632F3BAULL, 0x5504CC861C3D0556ULL, + 0xABBFA4E55FB26B8FULL, 0x41848B0AB3BACEB4ULL, 0xB334A273AA445D32ULL, + 0xBCA696F0A85AD881ULL, 0x24F6EC65B528D56CULL, 0x0CE1512E90F4524AULL, + 0x4E9DD79D5506D35AULL, 0x258905FAC6CE9779ULL, 0x2019295B3E109B33ULL, + 0xF8A9478B73A054CCULL, 0x2924F2F934417EB0ULL, 0x3993357D536D1BC4ULL, + 0x38A81AC21DB6FF8BULL, 0x47C4FBF17D6016BFULL, 0x1E0FAADD7667E3F5ULL, + 0x7ABCFF62938BEB96ULL, 0xA78DAD948FC179C9ULL, 0x8F1F98B72911E50DULL, + 0x61E48EAE27121A91ULL, 0x4D62F7AD31859808ULL, 0xECEBA345EF5CEAEBULL, + 0xF5CEB25EBC9684CEULL, 0xF633E20CB7F76221ULL, 0xA32CDF06AB8293E4ULL, + 0x985A202CA5EE2CA4ULL, 0xCF0B8447CC8A8FB1ULL, 0x9F765244979859A3ULL, + 0xA8D516B1A1240017ULL, 0x0BD7BA3EBB5DC726ULL, 0xE54BCA55B86ADB39ULL, + 0x1D7A3AFD6C478063ULL, 0x519EC608E7669EDDULL, 0x0E5715A2D149AA23ULL, + 0x177D4571848FF194ULL, 0xEEB55F3241014C22ULL, 0x0F5E5CA13A6E2EC2ULL, + 0x8029927B75F5C361ULL, 0xAD139FABC3D6E436ULL, 0x0D5DF1A94CCF402FULL, + 0x3E8BD948BEA5DFC8ULL, 0xA5A0D357BD3FF77EULL, 0xA2D12E251F74F645ULL, + 0x66FD9E525E81A082ULL, 0x2E0C90CE7F687A49ULL, 0xC2E8BCBEBA973BC5ULL, + 0x000001BCE509745FULL, 0x423777BBE6DAB3D6ULL, 0xD1661C7EAEF06EB5ULL, + 0xA1781F354DAACFD8ULL, 0x2D11284A2B16AFFCULL, 0xF1FC4F67FA891D1FULL, + 0x73ECC25DCB920ADAULL, 0xAE610C22C2A12651ULL, 0x96E0A810D356B78AULL, + 0x5A9A381F2FE7870FULL, 0xD5AD62EDE94E5530ULL, 0xD225E5E8368D1427ULL, + 0x65977B70C7AF4631ULL, 0x99F889B2DE39D74FULL, 0x233F30BF54E1D143ULL, + 0x9A9675D3D9A63C97ULL, 0x5470554FF334F9A8ULL, 0x166ACB744A4F5688ULL, + 0x70C74CAAB2E4AEADULL, 0xF0D091646F294D12ULL, 0x57B82A89684031D1ULL, + 0xEFD95A5A61BE0B6BULL, 0x2FBD12E969F2F29AULL, 0x9BD37013FEFF9FE8ULL, + 0x3F9B0404D6085A06ULL, 0x4940C1F3166CFE15ULL, 0x09542C4DCDF3DEFBULL, + 0xB4C5218385CD5CE3ULL, 0xC935B7DC4462A641ULL, 0x3417F8A68ED3B63FULL, + 0xB80959295B215B40ULL, 0xF99CDAEF3B8C8572ULL, 0x018C0614F8FCB95DULL, + 0x1B14ACCD1A3ACDF3ULL, 0x84D471F200BB732DULL, 0xC1A3110E95E8DA16ULL, + 0x430A7220BF1A82B8ULL, 0xB77E090D39DF210EULL, 0x5EF4BD9F3CD05E9DULL, + 0x9D4FF6DA7E57A444ULL, 0xDA1D60E183D4A5F8ULL, 0xB287C38417998E47ULL, + 0xFE3EDC121BB31886ULL, 0xC7FE3CCC980CCBEFULL, 0xE46FB590189BFD03ULL, + 0x3732FD469A4C57DCULL, 0x7EF700A07CF1AD65ULL, 0x59C64468A31D8859ULL, + 0x762FB0B4D45B61F6ULL, 0x155BAED099047718ULL, 0x68755E4C3D50BAA6ULL, + 0xE9214E7F22D8B4DFULL, 0x2ADDBF532EAC95F4ULL, 0x32AE3909B4BD0109ULL, + 0x834DF537B08E3450ULL, 0xFA209DA84220728DULL, 0x9E691D9B9EFE23F7ULL, + 0x0446D288C4AE8D7FULL, 0x7B4CC524E169785BULL, 0x21D87F0135CA1385ULL, + 0xCEBB400F137B8AA5ULL, 0x272E2B66580796BEULL, 0x3612264125C2B0DEULL, + 0x057702BDAD1EFBB2ULL, 0xD4BABB8EACF84BE9ULL, 0x91583139641BC67BULL, + 0x8BDC2DE08036E024ULL, 0x603C8156F49F68EDULL, 0xF7D236F7DBEF5111ULL, + 0x9727C4598AD21E80ULL, 0xA08A0896670A5FD7ULL, 0xCB4A8F4309EBA9CBULL, + 0x81AF564B0F7036A1ULL, 0xC0B99AA778199ABDULL, 0x959F1EC83FC8E952ULL, + 0x8C505077794A81B9ULL, 0x3ACAAF8F056338F0ULL, 0x07B43F50627A6778ULL, + 0x4A44AB49F5ECCC77ULL, 0x3BC3D6E4B679EE98ULL, 0x9CC0D4D1CF14108CULL, + 0x4406C00B206BC8A0ULL, 0x82A18854C8D72D89ULL, 0x67E366B35C3C432CULL, + 0xB923DD61102B37F2ULL, 0x56AB2779D884271DULL, 0xBE83E1B0FF1525AFULL, + 0xFB7C65D4217E49A9ULL, 0x6BDBE0E76D48E7D4ULL, 0x08DF828745D9179EULL, + 0x22EA6A9ADD53BD34ULL, 0xE36E141C5622200AULL, 0x7F805D1B8CB750EEULL, + 0xAFE5C7A59F58E837ULL, 0xE27F996A4FB1C23CULL, 0xD3867DFB0775F0D0ULL, + 0xD0E673DE6E88891AULL, 0x123AEB9EAFB86C25ULL, 0x30F1D5D5C145B895ULL, + 0xBB434A2DEE7269E7ULL, 0x78CB67ECF931FA38ULL, 0xF33B0372323BBF9CULL, + 0x52D66336FB279C74ULL, 0x505F33AC0AFB4EAAULL, 0xE8A5CD99A2CCE187ULL, + 0x534974801E2D30BBULL, 0x8D2D5711D5876D90ULL, 0x1F1A412891BC038EULL, + 0xD6E2E71D82E56648ULL, 0x74036C3A497732B7ULL, 0x89B67ED96361F5ABULL, + 0xFFED95D8F1EA02A2ULL, 0xE72B3BD61464D43DULL, 0xA6300F170BDC4820ULL, + 0xEBC18760ED78A77AULL }; + +const u64bit Tiger::SBOX2[256] = { + 0xE6A6BE5A05A12138ULL, 0xB5A122A5B4F87C98ULL, 0x563C6089140B6990ULL, + 0x4C46CB2E391F5DD5ULL, 0xD932ADDBC9B79434ULL, 0x08EA70E42015AFF5ULL, + 0xD765A6673E478CF1ULL, 0xC4FB757EAB278D99ULL, 0xDF11C6862D6E0692ULL, + 0xDDEB84F10D7F3B16ULL, 0x6F2EF604A665EA04ULL, 0x4A8E0F0FF0E0DFB3ULL, + 0xA5EDEEF83DBCBA51ULL, 0xFC4F0A2A0EA4371EULL, 0xE83E1DA85CB38429ULL, + 0xDC8FF882BA1B1CE2ULL, 0xCD45505E8353E80DULL, 0x18D19A00D4DB0717ULL, + 0x34A0CFEDA5F38101ULL, 0x0BE77E518887CAF2ULL, 0x1E341438B3C45136ULL, + 0xE05797F49089CCF9ULL, 0xFFD23F9DF2591D14ULL, 0x543DDA228595C5CDULL, + 0x661F81FD99052A33ULL, 0x8736E641DB0F7B76ULL, 0x15227725418E5307ULL, + 0xE25F7F46162EB2FAULL, 0x48A8B2126C13D9FEULL, 0xAFDC541792E76EEAULL, + 0x03D912BFC6D1898FULL, 0x31B1AAFA1B83F51BULL, 0xF1AC2796E42AB7D9ULL, + 0x40A3A7D7FCD2EBACULL, 0x1056136D0AFBBCC5ULL, 0x7889E1DD9A6D0C85ULL, + 0xD33525782A7974AAULL, 0xA7E25D09078AC09BULL, 0xBD4138B3EAC6EDD0ULL, + 0x920ABFBE71EB9E70ULL, 0xA2A5D0F54FC2625CULL, 0xC054E36B0B1290A3ULL, + 0xF6DD59FF62FE932BULL, 0x3537354511A8AC7DULL, 0xCA845E9172FADCD4ULL, + 0x84F82B60329D20DCULL, 0x79C62CE1CD672F18ULL, 0x8B09A2ADD124642CULL, + 0xD0C1E96A19D9E726ULL, 0x5A786A9B4BA9500CULL, 0x0E020336634C43F3ULL, + 0xC17B474AEB66D822ULL, 0x6A731AE3EC9BAAC2ULL, 0x8226667AE0840258ULL, + 0x67D4567691CAECA5ULL, 0x1D94155C4875ADB5ULL, 0x6D00FD985B813FDFULL, + 0x51286EFCB774CD06ULL, 0x5E8834471FA744AFULL, 0xF72CA0AEE761AE2EULL, + 0xBE40E4CDAEE8E09AULL, 0xE9970BBB5118F665ULL, 0x726E4BEB33DF1964ULL, + 0x703B000729199762ULL, 0x4631D816F5EF30A7ULL, 0xB880B5B51504A6BEULL, + 0x641793C37ED84B6CULL, 0x7B21ED77F6E97D96ULL, 0x776306312EF96B73ULL, + 0xAE528948E86FF3F4ULL, 0x53DBD7F286A3F8F8ULL, 0x16CADCE74CFC1063ULL, + 0x005C19BDFA52C6DDULL, 0x68868F5D64D46AD3ULL, 0x3A9D512CCF1E186AULL, + 0x367E62C2385660AEULL, 0xE359E7EA77DCB1D7ULL, 0x526C0773749ABE6EULL, + 0x735AE5F9D09F734BULL, 0x493FC7CC8A558BA8ULL, 0xB0B9C1533041AB45ULL, + 0x321958BA470A59BDULL, 0x852DB00B5F46C393ULL, 0x91209B2BD336B0E5ULL, + 0x6E604F7D659EF19FULL, 0xB99A8AE2782CCB24ULL, 0xCCF52AB6C814C4C7ULL, + 0x4727D9AFBE11727BULL, 0x7E950D0C0121B34DULL, 0x756F435670AD471FULL, + 0xF5ADD442615A6849ULL, 0x4E87E09980B9957AULL, 0x2ACFA1DF50AEE355ULL, + 0xD898263AFD2FD556ULL, 0xC8F4924DD80C8FD6ULL, 0xCF99CA3D754A173AULL, + 0xFE477BACAF91BF3CULL, 0xED5371F6D690C12DULL, 0x831A5C285E687094ULL, + 0xC5D3C90A3708A0A4ULL, 0x0F7F903717D06580ULL, 0x19F9BB13B8FDF27FULL, + 0xB1BD6F1B4D502843ULL, 0x1C761BA38FFF4012ULL, 0x0D1530C4E2E21F3BULL, + 0x8943CE69A7372C8AULL, 0xE5184E11FEB5CE66ULL, 0x618BDB80BD736621ULL, + 0x7D29BAD68B574D0BULL, 0x81BB613E25E6FE5BULL, 0x071C9C10BC07913FULL, + 0xC7BEEB7909AC2D97ULL, 0xC3E58D353BC5D757ULL, 0xEB017892F38F61E8ULL, + 0xD4EFFB9C9B1CC21AULL, 0x99727D26F494F7ABULL, 0xA3E063A2956B3E03ULL, + 0x9D4A8B9A4AA09C30ULL, 0x3F6AB7D500090FB4ULL, 0x9CC0F2A057268AC0ULL, + 0x3DEE9D2DEDBF42D1ULL, 0x330F49C87960A972ULL, 0xC6B2720287421B41ULL, + 0x0AC59EC07C00369CULL, 0xEF4EAC49CB353425ULL, 0xF450244EEF0129D8ULL, + 0x8ACC46E5CAF4DEB6ULL, 0x2FFEAB63989263F7ULL, 0x8F7CB9FE5D7A4578ULL, + 0x5BD8F7644E634635ULL, 0x427A7315BF2DC900ULL, 0x17D0C4AA2125261CULL, + 0x3992486C93518E50ULL, 0xB4CBFEE0A2D7D4C3ULL, 0x7C75D6202C5DDD8DULL, + 0xDBC295D8E35B6C61ULL, 0x60B369D302032B19ULL, 0xCE42685FDCE44132ULL, + 0x06F3DDB9DDF65610ULL, 0x8EA4D21DB5E148F0ULL, 0x20B0FCE62FCD496FULL, + 0x2C1B912358B0EE31ULL, 0xB28317B818F5A308ULL, 0xA89C1E189CA6D2CFULL, + 0x0C6B18576AAADBC8ULL, 0xB65DEAA91299FAE3ULL, 0xFB2B794B7F1027E7ULL, + 0x04E4317F443B5BEBULL, 0x4B852D325939D0A6ULL, 0xD5AE6BEEFB207FFCULL, + 0x309682B281C7D374ULL, 0xBAE309A194C3B475ULL, 0x8CC3F97B13B49F05ULL, + 0x98A9422FF8293967ULL, 0x244B16B01076FF7CULL, 0xF8BF571C663D67EEULL, + 0x1F0D6758EEE30DA1ULL, 0xC9B611D97ADEB9B7ULL, 0xB7AFD5887B6C57A2ULL, + 0x6290AE846B984FE1ULL, 0x94DF4CDEACC1A5FDULL, 0x058A5BD1C5483AFFULL, + 0x63166CC142BA3C37ULL, 0x8DB8526EB2F76F40ULL, 0xE10880036F0D6D4EULL, + 0x9E0523C9971D311DULL, 0x45EC2824CC7CD691ULL, 0x575B8359E62382C9ULL, + 0xFA9E400DC4889995ULL, 0xD1823ECB45721568ULL, 0xDAFD983B8206082FULL, + 0xAA7D29082386A8CBULL, 0x269FCD4403B87588ULL, 0x1B91F5F728BDD1E0ULL, + 0xE4669F39040201F6ULL, 0x7A1D7C218CF04ADEULL, 0x65623C29D79CE5CEULL, + 0x2368449096C00BB1ULL, 0xAB9BF1879DA503BAULL, 0xBC23ECB1A458058EULL, + 0x9A58DF01BB401ECCULL, 0xA070E868A85F143DULL, 0x4FF188307DF2239EULL, + 0x14D565B41A641183ULL, 0xEE13337452701602ULL, 0x950E3DCF3F285E09ULL, + 0x59930254B9C80953ULL, 0x3BF299408930DA6DULL, 0xA955943F53691387ULL, + 0xA15EDECAA9CB8784ULL, 0x29142127352BE9A0ULL, 0x76F0371FFF4E7AFBULL, + 0x0239F450274F2228ULL, 0xBB073AF01D5E868BULL, 0xBFC80571C10E96C1ULL, + 0xD267088568222E23ULL, 0x9671A3D48E80B5B0ULL, 0x55B5D38AE193BB81ULL, + 0x693AE2D0A18B04B8ULL, 0x5C48B4ECADD5335FULL, 0xFD743B194916A1CAULL, + 0x2577018134BE98C4ULL, 0xE77987E83C54A4ADULL, 0x28E11014DA33E1B9ULL, + 0x270CC59E226AA213ULL, 0x71495F756D1A5F60ULL, 0x9BE853FB60AFEF77ULL, + 0xADC786A7F7443DBFULL, 0x0904456173B29A82ULL, 0x58BC7A66C232BD5EULL, + 0xF306558C673AC8B2ULL, 0x41F639C6B6C9772AULL, 0x216DEFE99FDA35DAULL, + 0x11640CC71C7BE615ULL, 0x93C43694565C5527ULL, 0xEA038E6246777839ULL, + 0xF9ABF3CE5A3E2469ULL, 0x741E768D0FD312D2ULL, 0x0144B883CED652C6ULL, + 0xC20B5A5BA33F8552ULL, 0x1AE69633C3435A9DULL, 0x97A28CA4088CFDECULL, + 0x8824A43C1E96F420ULL, 0x37612FA66EEEA746ULL, 0x6B4CB165F9CF0E5AULL, + 0x43AA1C06A0ABFB4AULL, 0x7F4DC26FF162796BULL, 0x6CBACC8E54ED9B0FULL, + 0xA6B7FFEFD2BB253EULL, 0x2E25BC95B0A29D4FULL, 0x86D6A58BDEF1388CULL, + 0xDED74AC576B6F054ULL, 0x8030BDBC2B45805DULL, 0x3C81AF70E94D9289ULL, + 0x3EFF6DDA9E3100DBULL, 0xB38DC39FDFCC8847ULL, 0x123885528D17B87EULL, + 0xF2DA0ED240B1B642ULL, 0x44CEFADCD54BF9A9ULL, 0x1312200E433C7EE6ULL, + 0x9FFCC84F3A78C748ULL, 0xF0CD1F72248576BBULL, 0xEC6974053638CFE4ULL, + 0x2BA7B67C0CEC4E4CULL, 0xAC2F4DF3E5CE32EDULL, 0xCB33D14326EA4C11ULL, + 0xA4E9044CC77E58BCULL, 0x5F513293D934FCEFULL, 0x5DC9645506E55444ULL, + 0x50DE418F317DE40AULL, 0x388CB31A69DDE259ULL, 0x2DB4A83455820A86ULL, + 0x9010A91E84711AE9ULL, 0x4DF7F0B7B1498371ULL, 0xD62A2EABC0977179ULL, + 0x22FAC097AA8D5C0EULL }; + +const u64bit Tiger::SBOX3[256] = { + 0xF49FCC2FF1DAF39BULL, 0x487FD5C66FF29281ULL, 0xE8A30667FCDCA83FULL, + 0x2C9B4BE3D2FCCE63ULL, 0xDA3FF74B93FBBBC2ULL, 0x2FA165D2FE70BA66ULL, + 0xA103E279970E93D4ULL, 0xBECDEC77B0E45E71ULL, 0xCFB41E723985E497ULL, + 0xB70AAA025EF75017ULL, 0xD42309F03840B8E0ULL, 0x8EFC1AD035898579ULL, + 0x96C6920BE2B2ABC5ULL, 0x66AF4163375A9172ULL, 0x2174ABDCCA7127FBULL, + 0xB33CCEA64A72FF41ULL, 0xF04A4933083066A5ULL, 0x8D970ACDD7289AF5ULL, + 0x8F96E8E031C8C25EULL, 0xF3FEC02276875D47ULL, 0xEC7BF310056190DDULL, + 0xF5ADB0AEBB0F1491ULL, 0x9B50F8850FD58892ULL, 0x4975488358B74DE8ULL, + 0xA3354FF691531C61ULL, 0x0702BBE481D2C6EEULL, 0x89FB24057DEDED98ULL, + 0xAC3075138596E902ULL, 0x1D2D3580172772EDULL, 0xEB738FC28E6BC30DULL, + 0x5854EF8F63044326ULL, 0x9E5C52325ADD3BBEULL, 0x90AA53CF325C4623ULL, + 0xC1D24D51349DD067ULL, 0x2051CFEEA69EA624ULL, 0x13220F0A862E7E4FULL, + 0xCE39399404E04864ULL, 0xD9C42CA47086FCB7ULL, 0x685AD2238A03E7CCULL, + 0x066484B2AB2FF1DBULL, 0xFE9D5D70EFBF79ECULL, 0x5B13B9DD9C481854ULL, + 0x15F0D475ED1509ADULL, 0x0BEBCD060EC79851ULL, 0xD58C6791183AB7F8ULL, + 0xD1187C5052F3EEE4ULL, 0xC95D1192E54E82FFULL, 0x86EEA14CB9AC6CA2ULL, + 0x3485BEB153677D5DULL, 0xDD191D781F8C492AULL, 0xF60866BAA784EBF9ULL, + 0x518F643BA2D08C74ULL, 0x8852E956E1087C22ULL, 0xA768CB8DC410AE8DULL, + 0x38047726BFEC8E1AULL, 0xA67738B4CD3B45AAULL, 0xAD16691CEC0DDE19ULL, + 0xC6D4319380462E07ULL, 0xC5A5876D0BA61938ULL, 0x16B9FA1FA58FD840ULL, + 0x188AB1173CA74F18ULL, 0xABDA2F98C99C021FULL, 0x3E0580AB134AE816ULL, + 0x5F3B05B773645ABBULL, 0x2501A2BE5575F2F6ULL, 0x1B2F74004E7E8BA9ULL, + 0x1CD7580371E8D953ULL, 0x7F6ED89562764E30ULL, 0xB15926FF596F003DULL, + 0x9F65293DA8C5D6B9ULL, 0x6ECEF04DD690F84CULL, 0x4782275FFF33AF88ULL, + 0xE41433083F820801ULL, 0xFD0DFE409A1AF9B5ULL, 0x4325A3342CDB396BULL, + 0x8AE77E62B301B252ULL, 0xC36F9E9F6655615AULL, 0x85455A2D92D32C09ULL, + 0xF2C7DEA949477485ULL, 0x63CFB4C133A39EBAULL, 0x83B040CC6EBC5462ULL, + 0x3B9454C8FDB326B0ULL, 0x56F56A9E87FFD78CULL, 0x2DC2940D99F42BC6ULL, + 0x98F7DF096B096E2DULL, 0x19A6E01E3AD852BFULL, 0x42A99CCBDBD4B40BULL, + 0xA59998AF45E9C559ULL, 0x366295E807D93186ULL, 0x6B48181BFAA1F773ULL, + 0x1FEC57E2157A0A1DULL, 0x4667446AF6201AD5ULL, 0xE615EBCACFB0F075ULL, + 0xB8F31F4F68290778ULL, 0x22713ED6CE22D11EULL, 0x3057C1A72EC3C93BULL, + 0xCB46ACC37C3F1F2FULL, 0xDBB893FD02AAF50EULL, 0x331FD92E600B9FCFULL, + 0xA498F96148EA3AD6ULL, 0xA8D8426E8B6A83EAULL, 0xA089B274B7735CDCULL, + 0x87F6B3731E524A11ULL, 0x118808E5CBC96749ULL, 0x9906E4C7B19BD394ULL, + 0xAFED7F7E9B24A20CULL, 0x6509EADEEB3644A7ULL, 0x6C1EF1D3E8EF0EDEULL, + 0xB9C97D43E9798FB4ULL, 0xA2F2D784740C28A3ULL, 0x7B8496476197566FULL, + 0x7A5BE3E6B65F069DULL, 0xF96330ED78BE6F10ULL, 0xEEE60DE77A076A15ULL, + 0x2B4BEE4AA08B9BD0ULL, 0x6A56A63EC7B8894EULL, 0x02121359BA34FEF4ULL, + 0x4CBF99F8283703FCULL, 0x398071350CAF30C8ULL, 0xD0A77A89F017687AULL, + 0xF1C1A9EB9E423569ULL, 0x8C7976282DEE8199ULL, 0x5D1737A5DD1F7ABDULL, + 0x4F53433C09A9FA80ULL, 0xFA8B0C53DF7CA1D9ULL, 0x3FD9DCBC886CCB77ULL, + 0xC040917CA91B4720ULL, 0x7DD00142F9D1DCDFULL, 0x8476FC1D4F387B58ULL, + 0x23F8E7C5F3316503ULL, 0x032A2244E7E37339ULL, 0x5C87A5D750F5A74BULL, + 0x082B4CC43698992EULL, 0xDF917BECB858F63CULL, 0x3270B8FC5BF86DDAULL, + 0x10AE72BB29B5DD76ULL, 0x576AC94E7700362BULL, 0x1AD112DAC61EFB8FULL, + 0x691BC30EC5FAA427ULL, 0xFF246311CC327143ULL, 0x3142368E30E53206ULL, + 0x71380E31E02CA396ULL, 0x958D5C960AAD76F1ULL, 0xF8D6F430C16DA536ULL, + 0xC8FFD13F1BE7E1D2ULL, 0x7578AE66004DDBE1ULL, 0x05833F01067BE646ULL, + 0xBB34B5AD3BFE586DULL, 0x095F34C9A12B97F0ULL, 0x247AB64525D60CA8ULL, + 0xDCDBC6F3017477D1ULL, 0x4A2E14D4DECAD24DULL, 0xBDB5E6D9BE0A1EEBULL, + 0x2A7E70F7794301ABULL, 0xDEF42D8A270540FDULL, 0x01078EC0A34C22C1ULL, + 0xE5DE511AF4C16387ULL, 0x7EBB3A52BD9A330AULL, 0x77697857AA7D6435ULL, + 0x004E831603AE4C32ULL, 0xE7A21020AD78E312ULL, 0x9D41A70C6AB420F2ULL, + 0x28E06C18EA1141E6ULL, 0xD2B28CBD984F6B28ULL, 0x26B75F6C446E9D83ULL, + 0xBA47568C4D418D7FULL, 0xD80BADBFE6183D8EULL, 0x0E206D7F5F166044ULL, + 0xE258A43911CBCA3EULL, 0x723A1746B21DC0BCULL, 0xC7CAA854F5D7CDD3ULL, + 0x7CAC32883D261D9CULL, 0x7690C26423BA942CULL, 0x17E55524478042B8ULL, + 0xE0BE477656A2389FULL, 0x4D289B5E67AB2DA0ULL, 0x44862B9C8FBBFD31ULL, + 0xB47CC8049D141365ULL, 0x822C1B362B91C793ULL, 0x4EB14655FB13DFD8ULL, + 0x1ECBBA0714E2A97BULL, 0x6143459D5CDE5F14ULL, 0x53A8FBF1D5F0AC89ULL, + 0x97EA04D81C5E5B00ULL, 0x622181A8D4FDB3F3ULL, 0xE9BCD341572A1208ULL, + 0x1411258643CCE58AULL, 0x9144C5FEA4C6E0A4ULL, 0x0D33D06565CF620FULL, + 0x54A48D489F219CA1ULL, 0xC43E5EAC6D63C821ULL, 0xA9728B3A72770DAFULL, + 0xD7934E7B20DF87EFULL, 0xE35503B61A3E86E5ULL, 0xCAE321FBC819D504ULL, + 0x129A50B3AC60BFA6ULL, 0xCD5E68EA7E9FB6C3ULL, 0xB01C90199483B1C7ULL, + 0x3DE93CD5C295376CULL, 0xAED52EDF2AB9AD13ULL, 0x2E60F512C0A07884ULL, + 0xBC3D86A3E36210C9ULL, 0x35269D9B163951CEULL, 0x0C7D6E2AD0CDB5FAULL, + 0x59E86297D87F5733ULL, 0x298EF221898DB0E7ULL, 0x55000029D1A5AA7EULL, + 0x8BC08AE1B5061B45ULL, 0xC2C31C2B6C92703AULL, 0x94CC596BAF25EF42ULL, + 0x0A1D73DB22540456ULL, 0x04B6A0F9D9C4179AULL, 0xEFFDAFA2AE3D3C60ULL, + 0xF7C8075BB49496C4ULL, 0x9CC5C7141D1CD4E3ULL, 0x78BD1638218E5534ULL, + 0xB2F11568F850246AULL, 0xEDFABCFA9502BC29ULL, 0x796CE5F2DA23051BULL, + 0xAAE128B0DC93537CULL, 0x3A493DA0EE4B29AEULL, 0xB5DF6B2C416895D7ULL, + 0xFCABBD25122D7F37ULL, 0x70810B58105DC4B1ULL, 0xE10FDD37F7882A90ULL, + 0x524DCAB5518A3F5CULL, 0x3C9E85878451255BULL, 0x4029828119BD34E2ULL, + 0x74A05B6F5D3CECCBULL, 0xB610021542E13ECAULL, 0x0FF979D12F59E2ACULL, + 0x6037DA27E4F9CC50ULL, 0x5E92975A0DF1847DULL, 0xD66DE190D3E623FEULL, + 0x5032D6B87B568048ULL, 0x9A36B7CE8235216EULL, 0x80272A7A24F64B4AULL, + 0x93EFED8B8C6916F7ULL, 0x37DDBFF44CCE1555ULL, 0x4B95DB5D4B99BD25ULL, + 0x92D3FDA169812FC0ULL, 0xFB1A4A9A90660BB6ULL, 0x730C196946A4B9B2ULL, + 0x81E289AA7F49DA68ULL, 0x64669A0F83B1A05FULL, 0x27B3FF7D9644F48BULL, + 0xCC6B615C8DB675B3ULL, 0x674F20B9BCEBBE95ULL, 0x6F31238275655982ULL, + 0x5AE488713E45CF05ULL, 0xBF619F9954C21157ULL, 0xEABAC46040A8EAE9ULL, + 0x454C6FE9F2C0C1CDULL, 0x419CF6496412691CULL, 0xD3DC3BEF265B0F70ULL, + 0x6D0E60F5C3578A9EULL }; + +const u64bit Tiger::SBOX4[256] = { + 0x5B0E608526323C55ULL, 0x1A46C1A9FA1B59F5ULL, 0xA9E245A17C4C8FFAULL, + 0x65CA5159DB2955D7ULL, 0x05DB0A76CE35AFC2ULL, 0x81EAC77EA9113D45ULL, + 0x528EF88AB6AC0A0DULL, 0xA09EA253597BE3FFULL, 0x430DDFB3AC48CD56ULL, + 0xC4B3A67AF45CE46FULL, 0x4ECECFD8FBE2D05EULL, 0x3EF56F10B39935F0ULL, + 0x0B22D6829CD619C6ULL, 0x17FD460A74DF2069ULL, 0x6CF8CC8E8510ED40ULL, + 0xD6C824BF3A6ECAA7ULL, 0x61243D581A817049ULL, 0x048BACB6BBC163A2ULL, + 0xD9A38AC27D44CC32ULL, 0x7FDDFF5BAAF410ABULL, 0xAD6D495AA804824BULL, + 0xE1A6A74F2D8C9F94ULL, 0xD4F7851235DEE8E3ULL, 0xFD4B7F886540D893ULL, + 0x247C20042AA4BFDAULL, 0x096EA1C517D1327CULL, 0xD56966B4361A6685ULL, + 0x277DA5C31221057DULL, 0x94D59893A43ACFF7ULL, 0x64F0C51CCDC02281ULL, + 0x3D33BCC4FF6189DBULL, 0xE005CB184CE66AF1ULL, 0xFF5CCD1D1DB99BEAULL, + 0xB0B854A7FE42980FULL, 0x7BD46A6A718D4B9FULL, 0xD10FA8CC22A5FD8CULL, + 0xD31484952BE4BD31ULL, 0xC7FA975FCB243847ULL, 0x4886ED1E5846C407ULL, + 0x28CDDB791EB70B04ULL, 0xC2B00BE2F573417FULL, 0x5C9590452180F877ULL, + 0x7A6BDDFFF370EB00ULL, 0xCE509E38D6D9D6A4ULL, 0xEBEB0F00647FA702ULL, + 0x1DCC06CF76606F06ULL, 0xE4D9F28BA286FF0AULL, 0xD85A305DC918C262ULL, + 0x475B1D8732225F54ULL, 0x2D4FB51668CCB5FEULL, 0xA679B9D9D72BBA20ULL, + 0x53841C0D912D43A5ULL, 0x3B7EAA48BF12A4E8ULL, 0x781E0E47F22F1DDFULL, + 0xEFF20CE60AB50973ULL, 0x20D261D19DFFB742ULL, 0x16A12B03062A2E39ULL, + 0x1960EB2239650495ULL, 0x251C16FED50EB8B8ULL, 0x9AC0C330F826016EULL, + 0xED152665953E7671ULL, 0x02D63194A6369570ULL, 0x5074F08394B1C987ULL, + 0x70BA598C90B25CE1ULL, 0x794A15810B9742F6ULL, 0x0D5925E9FCAF8C6CULL, + 0x3067716CD868744EULL, 0x910AB077E8D7731BULL, 0x6A61BBDB5AC42F61ULL, + 0x93513EFBF0851567ULL, 0xF494724B9E83E9D5ULL, 0xE887E1985C09648DULL, + 0x34B1D3C675370CFDULL, 0xDC35E433BC0D255DULL, 0xD0AAB84234131BE0ULL, + 0x08042A50B48B7EAFULL, 0x9997C4EE44A3AB35ULL, 0x829A7B49201799D0ULL, + 0x263B8307B7C54441ULL, 0x752F95F4FD6A6CA6ULL, 0x927217402C08C6E5ULL, + 0x2A8AB754A795D9EEULL, 0xA442F7552F72943DULL, 0x2C31334E19781208ULL, + 0x4FA98D7CEAEE6291ULL, 0x55C3862F665DB309ULL, 0xBD0610175D53B1F3ULL, + 0x46FE6CB840413F27ULL, 0x3FE03792DF0CFA59ULL, 0xCFE700372EB85E8FULL, + 0xA7BE29E7ADBCE118ULL, 0xE544EE5CDE8431DDULL, 0x8A781B1B41F1873EULL, + 0xA5C94C78A0D2F0E7ULL, 0x39412E2877B60728ULL, 0xA1265EF3AFC9A62CULL, + 0xBCC2770C6A2506C5ULL, 0x3AB66DD5DCE1CE12ULL, 0xE65499D04A675B37ULL, + 0x7D8F523481BFD216ULL, 0x0F6F64FCEC15F389ULL, 0x74EFBE618B5B13C8ULL, + 0xACDC82B714273E1DULL, 0xDD40BFE003199D17ULL, 0x37E99257E7E061F8ULL, + 0xFA52626904775AAAULL, 0x8BBBF63A463D56F9ULL, 0xF0013F1543A26E64ULL, + 0xA8307E9F879EC898ULL, 0xCC4C27A4150177CCULL, 0x1B432F2CCA1D3348ULL, + 0xDE1D1F8F9F6FA013ULL, 0x606602A047A7DDD6ULL, 0xD237AB64CC1CB2C7ULL, + 0x9B938E7225FCD1D3ULL, 0xEC4E03708E0FF476ULL, 0xFEB2FBDA3D03C12DULL, + 0xAE0BCED2EE43889AULL, 0x22CB8923EBFB4F43ULL, 0x69360D013CF7396DULL, + 0x855E3602D2D4E022ULL, 0x073805BAD01F784CULL, 0x33E17A133852F546ULL, + 0xDF4874058AC7B638ULL, 0xBA92B29C678AA14AULL, 0x0CE89FC76CFAADCDULL, + 0x5F9D4E0908339E34ULL, 0xF1AFE9291F5923B9ULL, 0x6E3480F60F4A265FULL, + 0xEEBF3A2AB29B841CULL, 0xE21938A88F91B4ADULL, 0x57DFEFF845C6D3C3ULL, + 0x2F006B0BF62CAAF2ULL, 0x62F479EF6F75EE78ULL, 0x11A55AD41C8916A9ULL, + 0xF229D29084FED453ULL, 0x42F1C27B16B000E6ULL, 0x2B1F76749823C074ULL, + 0x4B76ECA3C2745360ULL, 0x8C98F463B91691BDULL, 0x14BCC93CF1ADE66AULL, + 0x8885213E6D458397ULL, 0x8E177DF0274D4711ULL, 0xB49B73B5503F2951ULL, + 0x10168168C3F96B6BULL, 0x0E3D963B63CAB0AEULL, 0x8DFC4B5655A1DB14ULL, + 0xF789F1356E14DE5CULL, 0x683E68AF4E51DAC1ULL, 0xC9A84F9D8D4B0FD9ULL, + 0x3691E03F52A0F9D1ULL, 0x5ED86E46E1878E80ULL, 0x3C711A0E99D07150ULL, + 0x5A0865B20C4E9310ULL, 0x56FBFC1FE4F0682EULL, 0xEA8D5DE3105EDF9BULL, + 0x71ABFDB12379187AULL, 0x2EB99DE1BEE77B9CULL, 0x21ECC0EA33CF4523ULL, + 0x59A4D7521805C7A1ULL, 0x3896F5EB56AE7C72ULL, 0xAA638F3DB18F75DCULL, + 0x9F39358DABE9808EULL, 0xB7DEFA91C00B72ACULL, 0x6B5541FD62492D92ULL, + 0x6DC6DEE8F92E4D5BULL, 0x353F57ABC4BEEA7EULL, 0x735769D6DA5690CEULL, + 0x0A234AA642391484ULL, 0xF6F9508028F80D9DULL, 0xB8E319A27AB3F215ULL, + 0x31AD9C1151341A4DULL, 0x773C22A57BEF5805ULL, 0x45C7561A07968633ULL, + 0xF913DA9E249DBE36ULL, 0xDA652D9B78A64C68ULL, 0x4C27A97F3BC334EFULL, + 0x76621220E66B17F4ULL, 0x967743899ACD7D0BULL, 0xF3EE5BCAE0ED6782ULL, + 0x409F753600C879FCULL, 0x06D09A39B5926DB6ULL, 0x6F83AEB0317AC588ULL, + 0x01E6CA4A86381F21ULL, 0x66FF3462D19F3025ULL, 0x72207C24DDFD3BFBULL, + 0x4AF6B6D3E2ECE2EBULL, 0x9C994DBEC7EA08DEULL, 0x49ACE597B09A8BC4ULL, + 0xB38C4766CF0797BAULL, 0x131B9373C57C2A75ULL, 0xB1822CCE61931E58ULL, + 0x9D7555B909BA1C0CULL, 0x127FAFDD937D11D2ULL, 0x29DA3BADC66D92E4ULL, + 0xA2C1D57154C2ECBCULL, 0x58C5134D82F6FE24ULL, 0x1C3AE3515B62274FULL, + 0xE907C82E01CB8126ULL, 0xF8ED091913E37FCBULL, 0x3249D8F9C80046C9ULL, + 0x80CF9BEDE388FB63ULL, 0x1881539A116CF19EULL, 0x5103F3F76BD52457ULL, + 0x15B7E6F5AE47F7A8ULL, 0xDBD7C6DED47E9CCFULL, 0x44E55C410228BB1AULL, + 0xB647D4255EDB4E99ULL, 0x5D11882BB8AAFC30ULL, 0xF5098BBB29D3212AULL, + 0x8FB5EA14E90296B3ULL, 0x677B942157DD025AULL, 0xFB58E7C0A390ACB5ULL, + 0x89D3674C83BD4A01ULL, 0x9E2DA4DF4BF3B93BULL, 0xFCC41E328CAB4829ULL, + 0x03F38C96BA582C52ULL, 0xCAD1BDBD7FD85DB2ULL, 0xBBB442C16082AE83ULL, + 0xB95FE86BA5DA9AB0ULL, 0xB22E04673771A93FULL, 0x845358C9493152D8ULL, + 0xBE2A488697B4541EULL, 0x95A2DC2DD38E6966ULL, 0xC02C11AC923C852BULL, + 0x2388B1990DF2A87BULL, 0x7C8008FA1B4F37BEULL, 0x1F70D0C84D54E503ULL, + 0x5490ADEC7ECE57D4ULL, 0x002B3C27D9063A3AULL, 0x7EAEA3848030A2BFULL, + 0xC602326DED2003C0ULL, 0x83A7287D69A94086ULL, 0xC57A5FCB30F57A8AULL, + 0xB56844E479EBE779ULL, 0xA373B40F05DCBCE9ULL, 0xD71A786E88570EE2ULL, + 0x879CBACDBDE8F6A0ULL, 0x976AD1BCC164A32FULL, 0xAB21E25E9666D78BULL, + 0x901063AAE5E5C33CULL, 0x9818B34448698D90ULL, 0xE36487AE3E1E8ABBULL, + 0xAFBDF931893BDCB4ULL, 0x6345A0DC5FBBD519ULL, 0x8628FE269B9465CAULL, + 0x1E5D01603F9C51ECULL, 0x4DE44006A15049B7ULL, 0xBF6C70E5F776CBB1ULL, + 0x411218F2EF552BEDULL, 0xCB0C0708705A36A3ULL, 0xE74D14754F986044ULL, + 0xCD56D9430EA8280EULL, 0xC12591D7535F5065ULL, 0xC83223F1720AEF96ULL, + 0xC3A0396F7363A51FULL }; + +} +/* +* Tiger +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Tiger Mixing Function +*/ +inline void mix(MemoryRegion& X) + { + X[0] -= X[7] ^ 0xA5A5A5A5A5A5A5A5ULL; + X[1] ^= X[0]; + X[2] += X[1]; + X[3] -= X[2] ^ ((~X[1]) << 19); + X[4] ^= X[3]; + X[5] += X[4]; + X[6] -= X[5] ^ ((~X[4]) >> 23); + X[7] ^= X[6]; + + X[0] += X[7]; + X[1] -= X[0] ^ ((~X[7]) << 19); + X[2] ^= X[1]; + X[3] += X[2]; + X[4] -= X[3] ^ ((~X[2]) >> 23); + X[5] ^= X[4]; + X[6] += X[5]; + X[7] -= X[6] ^ 0x0123456789ABCDEFULL; + } + +} + +/* +* Tiger Compression Function +*/ +void Tiger::compress_n(const byte input[], size_t blocks) + { + u64bit A = digest[0], B = digest[1], C = digest[2]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(&X[0], input, X.size()); + + pass(A, B, C, X, 5); mix(X); + pass(C, A, B, X, 7); mix(X); + pass(B, C, A, X, 9); + + for(size_t j = 3; j != passes; ++j) + { + mix(X); + pass(A, B, C, X, 9); + u64bit T = A; A = C; C = B; B = T; + } + + A = (digest[0] ^= A); + B = digest[1] = B - digest[1]; + C = (digest[2] += C); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Tiger::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); ++i) + output[i] = get_byte(7 - (i % 8), digest[i/8]); + } + +/* +* Tiger Pass +*/ +void Tiger::pass(u64bit& A, u64bit& B, u64bit& C, + const MemoryRegion& X, + byte mul) + { + C ^= X[0]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[1]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[2]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[3]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[4]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[5]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[6]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[7]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + } + +/* +* Clear memory of sensitive data +*/ +void Tiger::clear() + { + MDx_HashFunction::clear(); + zeroise(X); + digest[0] = 0x0123456789ABCDEFULL; + digest[1] = 0xFEDCBA9876543210ULL; + digest[2] = 0xF096A5B4C3B2E187ULL; + } + +/* +* Return the name of this type +*/ +std::string Tiger::name() const + { + return "Tiger(" + to_string(output_length()) + "," + to_string(passes) + ")"; + } + +/* +* Tiger Constructor +*/ +Tiger::Tiger(size_t hash_len, size_t passes) : + MDx_HashFunction(64, false, false), + X(8), + digest(3), + hash_len(hash_len), + passes(passes) + { + if(output_length() != 16 && output_length() != 20 && output_length() != 24) + throw Invalid_Argument("Tiger: Illegal hash output size: " + + to_string(output_length())); + + if(passes < 3) + throw Invalid_Argument("Tiger: Invalid number of passes: " + + to_string(passes)); + clear(); + } + +} +/* +* Diffusion Tables for Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u64bit Whirlpool::C0[256] = { +0x18186018C07830D8ULL, 0x23238C2305AF4626ULL, 0xC6C63FC67EF991B8ULL, 0xE8E887E8136FCDFBULL, +0x878726874CA113CBULL, 0xB8B8DAB8A9626D11ULL, 0x0101040108050209ULL, 0x4F4F214F426E9E0DULL, +0x3636D836ADEE6C9BULL, 0xA6A6A2A6590451FFULL, 0xD2D26FD2DEBDB90CULL, 0xF5F5F3F5FB06F70EULL, +0x7979F979EF80F296ULL, 0x6F6FA16F5FCEDE30ULL, 0x91917E91FCEF3F6DULL, 0x52525552AA07A4F8ULL, +0x60609D6027FDC047ULL, 0xBCBCCABC89766535ULL, 0x9B9B569BACCD2B37ULL, 0x8E8E028E048C018AULL, +0xA3A3B6A371155BD2ULL, 0x0C0C300C603C186CULL, 0x7B7BF17BFF8AF684ULL, 0x3535D435B5E16A80ULL, +0x1D1D741DE8693AF5ULL, 0xE0E0A7E05347DDB3ULL, 0xD7D77BD7F6ACB321ULL, 0xC2C22FC25EED999CULL, +0x2E2EB82E6D965C43ULL, 0x4B4B314B627A9629ULL, 0xFEFEDFFEA321E15DULL, 0x575741578216AED5ULL, +0x15155415A8412ABDULL, 0x7777C1779FB6EEE8ULL, 0x3737DC37A5EB6E92ULL, 0xE5E5B3E57B56D79EULL, +0x9F9F469F8CD92313ULL, 0xF0F0E7F0D317FD23ULL, 0x4A4A354A6A7F9420ULL, 0xDADA4FDA9E95A944ULL, +0x58587D58FA25B0A2ULL, 0xC9C903C906CA8FCFULL, 0x2929A429558D527CULL, 0x0A0A280A5022145AULL, +0xB1B1FEB1E14F7F50ULL, 0xA0A0BAA0691A5DC9ULL, 0x6B6BB16B7FDAD614ULL, 0x85852E855CAB17D9ULL, +0xBDBDCEBD8173673CULL, 0x5D5D695DD234BA8FULL, 0x1010401080502090ULL, 0xF4F4F7F4F303F507ULL, +0xCBCB0BCB16C08BDDULL, 0x3E3EF83EEDC67CD3ULL, 0x0505140528110A2DULL, 0x676781671FE6CE78ULL, +0xE4E4B7E47353D597ULL, 0x27279C2725BB4E02ULL, 0x4141194132588273ULL, 0x8B8B168B2C9D0BA7ULL, +0xA7A7A6A7510153F6ULL, 0x7D7DE97DCF94FAB2ULL, 0x95956E95DCFB3749ULL, 0xD8D847D88E9FAD56ULL, +0xFBFBCBFB8B30EB70ULL, 0xEEEE9FEE2371C1CDULL, 0x7C7CED7CC791F8BBULL, 0x6666856617E3CC71ULL, +0xDDDD53DDA68EA77BULL, 0x17175C17B84B2EAFULL, 0x4747014702468E45ULL, 0x9E9E429E84DC211AULL, +0xCACA0FCA1EC589D4ULL, 0x2D2DB42D75995A58ULL, 0xBFBFC6BF9179632EULL, 0x07071C07381B0E3FULL, +0xADAD8EAD012347ACULL, 0x5A5A755AEA2FB4B0ULL, 0x838336836CB51BEFULL, 0x3333CC3385FF66B6ULL, +0x636391633FF2C65CULL, 0x02020802100A0412ULL, 0xAAAA92AA39384993ULL, 0x7171D971AFA8E2DEULL, +0xC8C807C80ECF8DC6ULL, 0x19196419C87D32D1ULL, 0x494939497270923BULL, 0xD9D943D9869AAF5FULL, +0xF2F2EFF2C31DF931ULL, 0xE3E3ABE34B48DBA8ULL, 0x5B5B715BE22AB6B9ULL, 0x88881A8834920DBCULL, +0x9A9A529AA4C8293EULL, 0x262698262DBE4C0BULL, 0x3232C8328DFA64BFULL, 0xB0B0FAB0E94A7D59ULL, +0xE9E983E91B6ACFF2ULL, 0x0F0F3C0F78331E77ULL, 0xD5D573D5E6A6B733ULL, 0x80803A8074BA1DF4ULL, +0xBEBEC2BE997C6127ULL, 0xCDCD13CD26DE87EBULL, 0x3434D034BDE46889ULL, 0x48483D487A759032ULL, +0xFFFFDBFFAB24E354ULL, 0x7A7AF57AF78FF48DULL, 0x90907A90F4EA3D64ULL, 0x5F5F615FC23EBE9DULL, +0x202080201DA0403DULL, 0x6868BD6867D5D00FULL, 0x1A1A681AD07234CAULL, 0xAEAE82AE192C41B7ULL, +0xB4B4EAB4C95E757DULL, 0x54544D549A19A8CEULL, 0x93937693ECE53B7FULL, 0x222288220DAA442FULL, +0x64648D6407E9C863ULL, 0xF1F1E3F1DB12FF2AULL, 0x7373D173BFA2E6CCULL, 0x12124812905A2482ULL, +0x40401D403A5D807AULL, 0x0808200840281048ULL, 0xC3C32BC356E89B95ULL, 0xECEC97EC337BC5DFULL, +0xDBDB4BDB9690AB4DULL, 0xA1A1BEA1611F5FC0ULL, 0x8D8D0E8D1C830791ULL, 0x3D3DF43DF5C97AC8ULL, +0x97976697CCF1335BULL, 0x0000000000000000ULL, 0xCFCF1BCF36D483F9ULL, 0x2B2BAC2B4587566EULL, +0x7676C57697B3ECE1ULL, 0x8282328264B019E6ULL, 0xD6D67FD6FEA9B128ULL, 0x1B1B6C1BD87736C3ULL, +0xB5B5EEB5C15B7774ULL, 0xAFAF86AF112943BEULL, 0x6A6AB56A77DFD41DULL, 0x50505D50BA0DA0EAULL, +0x45450945124C8A57ULL, 0xF3F3EBF3CB18FB38ULL, 0x3030C0309DF060ADULL, 0xEFEF9BEF2B74C3C4ULL, +0x3F3FFC3FE5C37EDAULL, 0x55554955921CAAC7ULL, 0xA2A2B2A2791059DBULL, 0xEAEA8FEA0365C9E9ULL, +0x656589650FECCA6AULL, 0xBABAD2BAB9686903ULL, 0x2F2FBC2F65935E4AULL, 0xC0C027C04EE79D8EULL, +0xDEDE5FDEBE81A160ULL, 0x1C1C701CE06C38FCULL, 0xFDFDD3FDBB2EE746ULL, 0x4D4D294D52649A1FULL, +0x92927292E4E03976ULL, 0x7575C9758FBCEAFAULL, 0x06061806301E0C36ULL, 0x8A8A128A249809AEULL, +0xB2B2F2B2F940794BULL, 0xE6E6BFE66359D185ULL, 0x0E0E380E70361C7EULL, 0x1F1F7C1FF8633EE7ULL, +0x6262956237F7C455ULL, 0xD4D477D4EEA3B53AULL, 0xA8A89AA829324D81ULL, 0x96966296C4F43152ULL, +0xF9F9C3F99B3AEF62ULL, 0xC5C533C566F697A3ULL, 0x2525942535B14A10ULL, 0x59597959F220B2ABULL, +0x84842A8454AE15D0ULL, 0x7272D572B7A7E4C5ULL, 0x3939E439D5DD72ECULL, 0x4C4C2D4C5A619816ULL, +0x5E5E655ECA3BBC94ULL, 0x7878FD78E785F09FULL, 0x3838E038DDD870E5ULL, 0x8C8C0A8C14860598ULL, +0xD1D163D1C6B2BF17ULL, 0xA5A5AEA5410B57E4ULL, 0xE2E2AFE2434DD9A1ULL, 0x616199612FF8C24EULL, +0xB3B3F6B3F1457B42ULL, 0x2121842115A54234ULL, 0x9C9C4A9C94D62508ULL, 0x1E1E781EF0663CEEULL, +0x4343114322528661ULL, 0xC7C73BC776FC93B1ULL, 0xFCFCD7FCB32BE54FULL, 0x0404100420140824ULL, +0x51515951B208A2E3ULL, 0x99995E99BCC72F25ULL, 0x6D6DA96D4FC4DA22ULL, 0x0D0D340D68391A65ULL, +0xFAFACFFA8335E979ULL, 0xDFDF5BDFB684A369ULL, 0x7E7EE57ED79BFCA9ULL, 0x242490243DB44819ULL, +0x3B3BEC3BC5D776FEULL, 0xABAB96AB313D4B9AULL, 0xCECE1FCE3ED181F0ULL, 0x1111441188552299ULL, +0x8F8F068F0C890383ULL, 0x4E4E254E4A6B9C04ULL, 0xB7B7E6B7D1517366ULL, 0xEBEB8BEB0B60CBE0ULL, +0x3C3CF03CFDCC78C1ULL, 0x81813E817CBF1FFDULL, 0x94946A94D4FE3540ULL, 0xF7F7FBF7EB0CF31CULL, +0xB9B9DEB9A1676F18ULL, 0x13134C13985F268BULL, 0x2C2CB02C7D9C5851ULL, 0xD3D36BD3D6B8BB05ULL, +0xE7E7BBE76B5CD38CULL, 0x6E6EA56E57CBDC39ULL, 0xC4C437C46EF395AAULL, 0x03030C03180F061BULL, +0x565645568A13ACDCULL, 0x44440D441A49885EULL, 0x7F7FE17FDF9EFEA0ULL, 0xA9A99EA921374F88ULL, +0x2A2AA82A4D825467ULL, 0xBBBBD6BBB16D6B0AULL, 0xC1C123C146E29F87ULL, 0x53535153A202A6F1ULL, +0xDCDC57DCAE8BA572ULL, 0x0B0B2C0B58271653ULL, 0x9D9D4E9D9CD32701ULL, 0x6C6CAD6C47C1D82BULL, +0x3131C43195F562A4ULL, 0x7474CD7487B9E8F3ULL, 0xF6F6FFF6E309F115ULL, 0x464605460A438C4CULL, +0xACAC8AAC092645A5ULL, 0x89891E893C970FB5ULL, 0x14145014A04428B4ULL, 0xE1E1A3E15B42DFBAULL, +0x16165816B04E2CA6ULL, 0x3A3AE83ACDD274F7ULL, 0x6969B9696FD0D206ULL, 0x09092409482D1241ULL, +0x7070DD70A7ADE0D7ULL, 0xB6B6E2B6D954716FULL, 0xD0D067D0CEB7BD1EULL, 0xEDED93ED3B7EC7D6ULL, +0xCCCC17CC2EDB85E2ULL, 0x424215422A578468ULL, 0x98985A98B4C22D2CULL, 0xA4A4AAA4490E55EDULL, +0x2828A0285D885075ULL, 0x5C5C6D5CDA31B886ULL, 0xF8F8C7F8933FED6BULL, 0x8686228644A411C2ULL }; + +const u64bit Whirlpool::C1[256] = { +0xD818186018C07830ULL, 0x2623238C2305AF46ULL, 0xB8C6C63FC67EF991ULL, 0xFBE8E887E8136FCDULL, +0xCB878726874CA113ULL, 0x11B8B8DAB8A9626DULL, 0x0901010401080502ULL, 0x0D4F4F214F426E9EULL, +0x9B3636D836ADEE6CULL, 0xFFA6A6A2A6590451ULL, 0x0CD2D26FD2DEBDB9ULL, 0x0EF5F5F3F5FB06F7ULL, +0x967979F979EF80F2ULL, 0x306F6FA16F5FCEDEULL, 0x6D91917E91FCEF3FULL, 0xF852525552AA07A4ULL, +0x4760609D6027FDC0ULL, 0x35BCBCCABC897665ULL, 0x379B9B569BACCD2BULL, 0x8A8E8E028E048C01ULL, +0xD2A3A3B6A371155BULL, 0x6C0C0C300C603C18ULL, 0x847B7BF17BFF8AF6ULL, 0x803535D435B5E16AULL, +0xF51D1D741DE8693AULL, 0xB3E0E0A7E05347DDULL, 0x21D7D77BD7F6ACB3ULL, 0x9CC2C22FC25EED99ULL, +0x432E2EB82E6D965CULL, 0x294B4B314B627A96ULL, 0x5DFEFEDFFEA321E1ULL, 0xD5575741578216AEULL, +0xBD15155415A8412AULL, 0xE87777C1779FB6EEULL, 0x923737DC37A5EB6EULL, 0x9EE5E5B3E57B56D7ULL, +0x139F9F469F8CD923ULL, 0x23F0F0E7F0D317FDULL, 0x204A4A354A6A7F94ULL, 0x44DADA4FDA9E95A9ULL, +0xA258587D58FA25B0ULL, 0xCFC9C903C906CA8FULL, 0x7C2929A429558D52ULL, 0x5A0A0A280A502214ULL, +0x50B1B1FEB1E14F7FULL, 0xC9A0A0BAA0691A5DULL, 0x146B6BB16B7FDAD6ULL, 0xD985852E855CAB17ULL, +0x3CBDBDCEBD817367ULL, 0x8F5D5D695DD234BAULL, 0x9010104010805020ULL, 0x07F4F4F7F4F303F5ULL, +0xDDCBCB0BCB16C08BULL, 0xD33E3EF83EEDC67CULL, 0x2D0505140528110AULL, 0x78676781671FE6CEULL, +0x97E4E4B7E47353D5ULL, 0x0227279C2725BB4EULL, 0x7341411941325882ULL, 0xA78B8B168B2C9D0BULL, +0xF6A7A7A6A7510153ULL, 0xB27D7DE97DCF94FAULL, 0x4995956E95DCFB37ULL, 0x56D8D847D88E9FADULL, +0x70FBFBCBFB8B30EBULL, 0xCDEEEE9FEE2371C1ULL, 0xBB7C7CED7CC791F8ULL, 0x716666856617E3CCULL, +0x7BDDDD53DDA68EA7ULL, 0xAF17175C17B84B2EULL, 0x454747014702468EULL, 0x1A9E9E429E84DC21ULL, +0xD4CACA0FCA1EC589ULL, 0x582D2DB42D75995AULL, 0x2EBFBFC6BF917963ULL, 0x3F07071C07381B0EULL, +0xACADAD8EAD012347ULL, 0xB05A5A755AEA2FB4ULL, 0xEF838336836CB51BULL, 0xB63333CC3385FF66ULL, +0x5C636391633FF2C6ULL, 0x1202020802100A04ULL, 0x93AAAA92AA393849ULL, 0xDE7171D971AFA8E2ULL, +0xC6C8C807C80ECF8DULL, 0xD119196419C87D32ULL, 0x3B49493949727092ULL, 0x5FD9D943D9869AAFULL, +0x31F2F2EFF2C31DF9ULL, 0xA8E3E3ABE34B48DBULL, 0xB95B5B715BE22AB6ULL, 0xBC88881A8834920DULL, +0x3E9A9A529AA4C829ULL, 0x0B262698262DBE4CULL, 0xBF3232C8328DFA64ULL, 0x59B0B0FAB0E94A7DULL, +0xF2E9E983E91B6ACFULL, 0x770F0F3C0F78331EULL, 0x33D5D573D5E6A6B7ULL, 0xF480803A8074BA1DULL, +0x27BEBEC2BE997C61ULL, 0xEBCDCD13CD26DE87ULL, 0x893434D034BDE468ULL, 0x3248483D487A7590ULL, +0x54FFFFDBFFAB24E3ULL, 0x8D7A7AF57AF78FF4ULL, 0x6490907A90F4EA3DULL, 0x9D5F5F615FC23EBEULL, +0x3D202080201DA040ULL, 0x0F6868BD6867D5D0ULL, 0xCA1A1A681AD07234ULL, 0xB7AEAE82AE192C41ULL, +0x7DB4B4EAB4C95E75ULL, 0xCE54544D549A19A8ULL, 0x7F93937693ECE53BULL, 0x2F222288220DAA44ULL, +0x6364648D6407E9C8ULL, 0x2AF1F1E3F1DB12FFULL, 0xCC7373D173BFA2E6ULL, 0x8212124812905A24ULL, +0x7A40401D403A5D80ULL, 0x4808082008402810ULL, 0x95C3C32BC356E89BULL, 0xDFECEC97EC337BC5ULL, +0x4DDBDB4BDB9690ABULL, 0xC0A1A1BEA1611F5FULL, 0x918D8D0E8D1C8307ULL, 0xC83D3DF43DF5C97AULL, +0x5B97976697CCF133ULL, 0x0000000000000000ULL, 0xF9CFCF1BCF36D483ULL, 0x6E2B2BAC2B458756ULL, +0xE17676C57697B3ECULL, 0xE68282328264B019ULL, 0x28D6D67FD6FEA9B1ULL, 0xC31B1B6C1BD87736ULL, +0x74B5B5EEB5C15B77ULL, 0xBEAFAF86AF112943ULL, 0x1D6A6AB56A77DFD4ULL, 0xEA50505D50BA0DA0ULL, +0x5745450945124C8AULL, 0x38F3F3EBF3CB18FBULL, 0xAD3030C0309DF060ULL, 0xC4EFEF9BEF2B74C3ULL, +0xDA3F3FFC3FE5C37EULL, 0xC755554955921CAAULL, 0xDBA2A2B2A2791059ULL, 0xE9EAEA8FEA0365C9ULL, +0x6A656589650FECCAULL, 0x03BABAD2BAB96869ULL, 0x4A2F2FBC2F65935EULL, 0x8EC0C027C04EE79DULL, +0x60DEDE5FDEBE81A1ULL, 0xFC1C1C701CE06C38ULL, 0x46FDFDD3FDBB2EE7ULL, 0x1F4D4D294D52649AULL, +0x7692927292E4E039ULL, 0xFA7575C9758FBCEAULL, 0x3606061806301E0CULL, 0xAE8A8A128A249809ULL, +0x4BB2B2F2B2F94079ULL, 0x85E6E6BFE66359D1ULL, 0x7E0E0E380E70361CULL, 0xE71F1F7C1FF8633EULL, +0x556262956237F7C4ULL, 0x3AD4D477D4EEA3B5ULL, 0x81A8A89AA829324DULL, 0x5296966296C4F431ULL, +0x62F9F9C3F99B3AEFULL, 0xA3C5C533C566F697ULL, 0x102525942535B14AULL, 0xAB59597959F220B2ULL, +0xD084842A8454AE15ULL, 0xC57272D572B7A7E4ULL, 0xEC3939E439D5DD72ULL, 0x164C4C2D4C5A6198ULL, +0x945E5E655ECA3BBCULL, 0x9F7878FD78E785F0ULL, 0xE53838E038DDD870ULL, 0x988C8C0A8C148605ULL, +0x17D1D163D1C6B2BFULL, 0xE4A5A5AEA5410B57ULL, 0xA1E2E2AFE2434DD9ULL, 0x4E616199612FF8C2ULL, +0x42B3B3F6B3F1457BULL, 0x342121842115A542ULL, 0x089C9C4A9C94D625ULL, 0xEE1E1E781EF0663CULL, +0x6143431143225286ULL, 0xB1C7C73BC776FC93ULL, 0x4FFCFCD7FCB32BE5ULL, 0x2404041004201408ULL, +0xE351515951B208A2ULL, 0x2599995E99BCC72FULL, 0x226D6DA96D4FC4DAULL, 0x650D0D340D68391AULL, +0x79FAFACFFA8335E9ULL, 0x69DFDF5BDFB684A3ULL, 0xA97E7EE57ED79BFCULL, 0x19242490243DB448ULL, +0xFE3B3BEC3BC5D776ULL, 0x9AABAB96AB313D4BULL, 0xF0CECE1FCE3ED181ULL, 0x9911114411885522ULL, +0x838F8F068F0C8903ULL, 0x044E4E254E4A6B9CULL, 0x66B7B7E6B7D15173ULL, 0xE0EBEB8BEB0B60CBULL, +0xC13C3CF03CFDCC78ULL, 0xFD81813E817CBF1FULL, 0x4094946A94D4FE35ULL, 0x1CF7F7FBF7EB0CF3ULL, +0x18B9B9DEB9A1676FULL, 0x8B13134C13985F26ULL, 0x512C2CB02C7D9C58ULL, 0x05D3D36BD3D6B8BBULL, +0x8CE7E7BBE76B5CD3ULL, 0x396E6EA56E57CBDCULL, 0xAAC4C437C46EF395ULL, 0x1B03030C03180F06ULL, +0xDC565645568A13ACULL, 0x5E44440D441A4988ULL, 0xA07F7FE17FDF9EFEULL, 0x88A9A99EA921374FULL, +0x672A2AA82A4D8254ULL, 0x0ABBBBD6BBB16D6BULL, 0x87C1C123C146E29FULL, 0xF153535153A202A6ULL, +0x72DCDC57DCAE8BA5ULL, 0x530B0B2C0B582716ULL, 0x019D9D4E9D9CD327ULL, 0x2B6C6CAD6C47C1D8ULL, +0xA43131C43195F562ULL, 0xF37474CD7487B9E8ULL, 0x15F6F6FFF6E309F1ULL, 0x4C464605460A438CULL, +0xA5ACAC8AAC092645ULL, 0xB589891E893C970FULL, 0xB414145014A04428ULL, 0xBAE1E1A3E15B42DFULL, +0xA616165816B04E2CULL, 0xF73A3AE83ACDD274ULL, 0x066969B9696FD0D2ULL, 0x4109092409482D12ULL, +0xD77070DD70A7ADE0ULL, 0x6FB6B6E2B6D95471ULL, 0x1ED0D067D0CEB7BDULL, 0xD6EDED93ED3B7EC7ULL, +0xE2CCCC17CC2EDB85ULL, 0x68424215422A5784ULL, 0x2C98985A98B4C22DULL, 0xEDA4A4AAA4490E55ULL, +0x752828A0285D8850ULL, 0x865C5C6D5CDA31B8ULL, 0x6BF8F8C7F8933FEDULL, 0xC28686228644A411ULL }; + +const u64bit Whirlpool::C2[256] = { +0x30D818186018C078ULL, 0x462623238C2305AFULL, 0x91B8C6C63FC67EF9ULL, 0xCDFBE8E887E8136FULL, +0x13CB878726874CA1ULL, 0x6D11B8B8DAB8A962ULL, 0x0209010104010805ULL, 0x9E0D4F4F214F426EULL, +0x6C9B3636D836ADEEULL, 0x51FFA6A6A2A65904ULL, 0xB90CD2D26FD2DEBDULL, 0xF70EF5F5F3F5FB06ULL, +0xF2967979F979EF80ULL, 0xDE306F6FA16F5FCEULL, 0x3F6D91917E91FCEFULL, 0xA4F852525552AA07ULL, +0xC04760609D6027FDULL, 0x6535BCBCCABC8976ULL, 0x2B379B9B569BACCDULL, 0x018A8E8E028E048CULL, +0x5BD2A3A3B6A37115ULL, 0x186C0C0C300C603CULL, 0xF6847B7BF17BFF8AULL, 0x6A803535D435B5E1ULL, +0x3AF51D1D741DE869ULL, 0xDDB3E0E0A7E05347ULL, 0xB321D7D77BD7F6ACULL, 0x999CC2C22FC25EEDULL, +0x5C432E2EB82E6D96ULL, 0x96294B4B314B627AULL, 0xE15DFEFEDFFEA321ULL, 0xAED5575741578216ULL, +0x2ABD15155415A841ULL, 0xEEE87777C1779FB6ULL, 0x6E923737DC37A5EBULL, 0xD79EE5E5B3E57B56ULL, +0x23139F9F469F8CD9ULL, 0xFD23F0F0E7F0D317ULL, 0x94204A4A354A6A7FULL, 0xA944DADA4FDA9E95ULL, +0xB0A258587D58FA25ULL, 0x8FCFC9C903C906CAULL, 0x527C2929A429558DULL, 0x145A0A0A280A5022ULL, +0x7F50B1B1FEB1E14FULL, 0x5DC9A0A0BAA0691AULL, 0xD6146B6BB16B7FDAULL, 0x17D985852E855CABULL, +0x673CBDBDCEBD8173ULL, 0xBA8F5D5D695DD234ULL, 0x2090101040108050ULL, 0xF507F4F4F7F4F303ULL, +0x8BDDCBCB0BCB16C0ULL, 0x7CD33E3EF83EEDC6ULL, 0x0A2D050514052811ULL, 0xCE78676781671FE6ULL, +0xD597E4E4B7E47353ULL, 0x4E0227279C2725BBULL, 0x8273414119413258ULL, 0x0BA78B8B168B2C9DULL, +0x53F6A7A7A6A75101ULL, 0xFAB27D7DE97DCF94ULL, 0x374995956E95DCFBULL, 0xAD56D8D847D88E9FULL, +0xEB70FBFBCBFB8B30ULL, 0xC1CDEEEE9FEE2371ULL, 0xF8BB7C7CED7CC791ULL, 0xCC716666856617E3ULL, +0xA77BDDDD53DDA68EULL, 0x2EAF17175C17B84BULL, 0x8E45474701470246ULL, 0x211A9E9E429E84DCULL, +0x89D4CACA0FCA1EC5ULL, 0x5A582D2DB42D7599ULL, 0x632EBFBFC6BF9179ULL, 0x0E3F07071C07381BULL, +0x47ACADAD8EAD0123ULL, 0xB4B05A5A755AEA2FULL, 0x1BEF838336836CB5ULL, 0x66B63333CC3385FFULL, +0xC65C636391633FF2ULL, 0x041202020802100AULL, 0x4993AAAA92AA3938ULL, 0xE2DE7171D971AFA8ULL, +0x8DC6C8C807C80ECFULL, 0x32D119196419C87DULL, 0x923B494939497270ULL, 0xAF5FD9D943D9869AULL, +0xF931F2F2EFF2C31DULL, 0xDBA8E3E3ABE34B48ULL, 0xB6B95B5B715BE22AULL, 0x0DBC88881A883492ULL, +0x293E9A9A529AA4C8ULL, 0x4C0B262698262DBEULL, 0x64BF3232C8328DFAULL, 0x7D59B0B0FAB0E94AULL, +0xCFF2E9E983E91B6AULL, 0x1E770F0F3C0F7833ULL, 0xB733D5D573D5E6A6ULL, 0x1DF480803A8074BAULL, +0x6127BEBEC2BE997CULL, 0x87EBCDCD13CD26DEULL, 0x68893434D034BDE4ULL, 0x903248483D487A75ULL, +0xE354FFFFDBFFAB24ULL, 0xF48D7A7AF57AF78FULL, 0x3D6490907A90F4EAULL, 0xBE9D5F5F615FC23EULL, +0x403D202080201DA0ULL, 0xD00F6868BD6867D5ULL, 0x34CA1A1A681AD072ULL, 0x41B7AEAE82AE192CULL, +0x757DB4B4EAB4C95EULL, 0xA8CE54544D549A19ULL, 0x3B7F93937693ECE5ULL, 0x442F222288220DAAULL, +0xC86364648D6407E9ULL, 0xFF2AF1F1E3F1DB12ULL, 0xE6CC7373D173BFA2ULL, 0x248212124812905AULL, +0x807A40401D403A5DULL, 0x1048080820084028ULL, 0x9B95C3C32BC356E8ULL, 0xC5DFECEC97EC337BULL, +0xAB4DDBDB4BDB9690ULL, 0x5FC0A1A1BEA1611FULL, 0x07918D8D0E8D1C83ULL, 0x7AC83D3DF43DF5C9ULL, +0x335B97976697CCF1ULL, 0x0000000000000000ULL, 0x83F9CFCF1BCF36D4ULL, 0x566E2B2BAC2B4587ULL, +0xECE17676C57697B3ULL, 0x19E68282328264B0ULL, 0xB128D6D67FD6FEA9ULL, 0x36C31B1B6C1BD877ULL, +0x7774B5B5EEB5C15BULL, 0x43BEAFAF86AF1129ULL, 0xD41D6A6AB56A77DFULL, 0xA0EA50505D50BA0DULL, +0x8A5745450945124CULL, 0xFB38F3F3EBF3CB18ULL, 0x60AD3030C0309DF0ULL, 0xC3C4EFEF9BEF2B74ULL, +0x7EDA3F3FFC3FE5C3ULL, 0xAAC755554955921CULL, 0x59DBA2A2B2A27910ULL, 0xC9E9EAEA8FEA0365ULL, +0xCA6A656589650FECULL, 0x6903BABAD2BAB968ULL, 0x5E4A2F2FBC2F6593ULL, 0x9D8EC0C027C04EE7ULL, +0xA160DEDE5FDEBE81ULL, 0x38FC1C1C701CE06CULL, 0xE746FDFDD3FDBB2EULL, 0x9A1F4D4D294D5264ULL, +0x397692927292E4E0ULL, 0xEAFA7575C9758FBCULL, 0x0C3606061806301EULL, 0x09AE8A8A128A2498ULL, +0x794BB2B2F2B2F940ULL, 0xD185E6E6BFE66359ULL, 0x1C7E0E0E380E7036ULL, 0x3EE71F1F7C1FF863ULL, +0xC4556262956237F7ULL, 0xB53AD4D477D4EEA3ULL, 0x4D81A8A89AA82932ULL, 0x315296966296C4F4ULL, +0xEF62F9F9C3F99B3AULL, 0x97A3C5C533C566F6ULL, 0x4A102525942535B1ULL, 0xB2AB59597959F220ULL, +0x15D084842A8454AEULL, 0xE4C57272D572B7A7ULL, 0x72EC3939E439D5DDULL, 0x98164C4C2D4C5A61ULL, +0xBC945E5E655ECA3BULL, 0xF09F7878FD78E785ULL, 0x70E53838E038DDD8ULL, 0x05988C8C0A8C1486ULL, +0xBF17D1D163D1C6B2ULL, 0x57E4A5A5AEA5410BULL, 0xD9A1E2E2AFE2434DULL, 0xC24E616199612FF8ULL, +0x7B42B3B3F6B3F145ULL, 0x42342121842115A5ULL, 0x25089C9C4A9C94D6ULL, 0x3CEE1E1E781EF066ULL, +0x8661434311432252ULL, 0x93B1C7C73BC776FCULL, 0xE54FFCFCD7FCB32BULL, 0x0824040410042014ULL, +0xA2E351515951B208ULL, 0x2F2599995E99BCC7ULL, 0xDA226D6DA96D4FC4ULL, 0x1A650D0D340D6839ULL, +0xE979FAFACFFA8335ULL, 0xA369DFDF5BDFB684ULL, 0xFCA97E7EE57ED79BULL, 0x4819242490243DB4ULL, +0x76FE3B3BEC3BC5D7ULL, 0x4B9AABAB96AB313DULL, 0x81F0CECE1FCE3ED1ULL, 0x2299111144118855ULL, +0x03838F8F068F0C89ULL, 0x9C044E4E254E4A6BULL, 0x7366B7B7E6B7D151ULL, 0xCBE0EBEB8BEB0B60ULL, +0x78C13C3CF03CFDCCULL, 0x1FFD81813E817CBFULL, 0x354094946A94D4FEULL, 0xF31CF7F7FBF7EB0CULL, +0x6F18B9B9DEB9A167ULL, 0x268B13134C13985FULL, 0x58512C2CB02C7D9CULL, 0xBB05D3D36BD3D6B8ULL, +0xD38CE7E7BBE76B5CULL, 0xDC396E6EA56E57CBULL, 0x95AAC4C437C46EF3ULL, 0x061B03030C03180FULL, +0xACDC565645568A13ULL, 0x885E44440D441A49ULL, 0xFEA07F7FE17FDF9EULL, 0x4F88A9A99EA92137ULL, +0x54672A2AA82A4D82ULL, 0x6B0ABBBBD6BBB16DULL, 0x9F87C1C123C146E2ULL, 0xA6F153535153A202ULL, +0xA572DCDC57DCAE8BULL, 0x16530B0B2C0B5827ULL, 0x27019D9D4E9D9CD3ULL, 0xD82B6C6CAD6C47C1ULL, +0x62A43131C43195F5ULL, 0xE8F37474CD7487B9ULL, 0xF115F6F6FFF6E309ULL, 0x8C4C464605460A43ULL, +0x45A5ACAC8AAC0926ULL, 0x0FB589891E893C97ULL, 0x28B414145014A044ULL, 0xDFBAE1E1A3E15B42ULL, +0x2CA616165816B04EULL, 0x74F73A3AE83ACDD2ULL, 0xD2066969B9696FD0ULL, 0x124109092409482DULL, +0xE0D77070DD70A7ADULL, 0x716FB6B6E2B6D954ULL, 0xBD1ED0D067D0CEB7ULL, 0xC7D6EDED93ED3B7EULL, +0x85E2CCCC17CC2EDBULL, 0x8468424215422A57ULL, 0x2D2C98985A98B4C2ULL, 0x55EDA4A4AAA4490EULL, +0x50752828A0285D88ULL, 0xB8865C5C6D5CDA31ULL, 0xED6BF8F8C7F8933FULL, 0x11C28686228644A4ULL }; + +const u64bit Whirlpool::C3[256] = { +0x7830D818186018C0ULL, 0xAF462623238C2305ULL, 0xF991B8C6C63FC67EULL, 0x6FCDFBE8E887E813ULL, +0xA113CB878726874CULL, 0x626D11B8B8DAB8A9ULL, 0x0502090101040108ULL, 0x6E9E0D4F4F214F42ULL, +0xEE6C9B3636D836ADULL, 0x0451FFA6A6A2A659ULL, 0xBDB90CD2D26FD2DEULL, 0x06F70EF5F5F3F5FBULL, +0x80F2967979F979EFULL, 0xCEDE306F6FA16F5FULL, 0xEF3F6D91917E91FCULL, 0x07A4F852525552AAULL, +0xFDC04760609D6027ULL, 0x766535BCBCCABC89ULL, 0xCD2B379B9B569BACULL, 0x8C018A8E8E028E04ULL, +0x155BD2A3A3B6A371ULL, 0x3C186C0C0C300C60ULL, 0x8AF6847B7BF17BFFULL, 0xE16A803535D435B5ULL, +0x693AF51D1D741DE8ULL, 0x47DDB3E0E0A7E053ULL, 0xACB321D7D77BD7F6ULL, 0xED999CC2C22FC25EULL, +0x965C432E2EB82E6DULL, 0x7A96294B4B314B62ULL, 0x21E15DFEFEDFFEA3ULL, 0x16AED55757415782ULL, +0x412ABD15155415A8ULL, 0xB6EEE87777C1779FULL, 0xEB6E923737DC37A5ULL, 0x56D79EE5E5B3E57BULL, +0xD923139F9F469F8CULL, 0x17FD23F0F0E7F0D3ULL, 0x7F94204A4A354A6AULL, 0x95A944DADA4FDA9EULL, +0x25B0A258587D58FAULL, 0xCA8FCFC9C903C906ULL, 0x8D527C2929A42955ULL, 0x22145A0A0A280A50ULL, +0x4F7F50B1B1FEB1E1ULL, 0x1A5DC9A0A0BAA069ULL, 0xDAD6146B6BB16B7FULL, 0xAB17D985852E855CULL, +0x73673CBDBDCEBD81ULL, 0x34BA8F5D5D695DD2ULL, 0x5020901010401080ULL, 0x03F507F4F4F7F4F3ULL, +0xC08BDDCBCB0BCB16ULL, 0xC67CD33E3EF83EEDULL, 0x110A2D0505140528ULL, 0xE6CE78676781671FULL, +0x53D597E4E4B7E473ULL, 0xBB4E0227279C2725ULL, 0x5882734141194132ULL, 0x9D0BA78B8B168B2CULL, +0x0153F6A7A7A6A751ULL, 0x94FAB27D7DE97DCFULL, 0xFB374995956E95DCULL, 0x9FAD56D8D847D88EULL, +0x30EB70FBFBCBFB8BULL, 0x71C1CDEEEE9FEE23ULL, 0x91F8BB7C7CED7CC7ULL, 0xE3CC716666856617ULL, +0x8EA77BDDDD53DDA6ULL, 0x4B2EAF17175C17B8ULL, 0x468E454747014702ULL, 0xDC211A9E9E429E84ULL, +0xC589D4CACA0FCA1EULL, 0x995A582D2DB42D75ULL, 0x79632EBFBFC6BF91ULL, 0x1B0E3F07071C0738ULL, +0x2347ACADAD8EAD01ULL, 0x2FB4B05A5A755AEAULL, 0xB51BEF838336836CULL, 0xFF66B63333CC3385ULL, +0xF2C65C636391633FULL, 0x0A04120202080210ULL, 0x384993AAAA92AA39ULL, 0xA8E2DE7171D971AFULL, +0xCF8DC6C8C807C80EULL, 0x7D32D119196419C8ULL, 0x70923B4949394972ULL, 0x9AAF5FD9D943D986ULL, +0x1DF931F2F2EFF2C3ULL, 0x48DBA8E3E3ABE34BULL, 0x2AB6B95B5B715BE2ULL, 0x920DBC88881A8834ULL, +0xC8293E9A9A529AA4ULL, 0xBE4C0B262698262DULL, 0xFA64BF3232C8328DULL, 0x4A7D59B0B0FAB0E9ULL, +0x6ACFF2E9E983E91BULL, 0x331E770F0F3C0F78ULL, 0xA6B733D5D573D5E6ULL, 0xBA1DF480803A8074ULL, +0x7C6127BEBEC2BE99ULL, 0xDE87EBCDCD13CD26ULL, 0xE468893434D034BDULL, 0x75903248483D487AULL, +0x24E354FFFFDBFFABULL, 0x8FF48D7A7AF57AF7ULL, 0xEA3D6490907A90F4ULL, 0x3EBE9D5F5F615FC2ULL, +0xA0403D202080201DULL, 0xD5D00F6868BD6867ULL, 0x7234CA1A1A681AD0ULL, 0x2C41B7AEAE82AE19ULL, +0x5E757DB4B4EAB4C9ULL, 0x19A8CE54544D549AULL, 0xE53B7F93937693ECULL, 0xAA442F222288220DULL, +0xE9C86364648D6407ULL, 0x12FF2AF1F1E3F1DBULL, 0xA2E6CC7373D173BFULL, 0x5A24821212481290ULL, +0x5D807A40401D403AULL, 0x2810480808200840ULL, 0xE89B95C3C32BC356ULL, 0x7BC5DFECEC97EC33ULL, +0x90AB4DDBDB4BDB96ULL, 0x1F5FC0A1A1BEA161ULL, 0x8307918D8D0E8D1CULL, 0xC97AC83D3DF43DF5ULL, +0xF1335B97976697CCULL, 0x0000000000000000ULL, 0xD483F9CFCF1BCF36ULL, 0x87566E2B2BAC2B45ULL, +0xB3ECE17676C57697ULL, 0xB019E68282328264ULL, 0xA9B128D6D67FD6FEULL, 0x7736C31B1B6C1BD8ULL, +0x5B7774B5B5EEB5C1ULL, 0x2943BEAFAF86AF11ULL, 0xDFD41D6A6AB56A77ULL, 0x0DA0EA50505D50BAULL, +0x4C8A574545094512ULL, 0x18FB38F3F3EBF3CBULL, 0xF060AD3030C0309DULL, 0x74C3C4EFEF9BEF2BULL, +0xC37EDA3F3FFC3FE5ULL, 0x1CAAC75555495592ULL, 0x1059DBA2A2B2A279ULL, 0x65C9E9EAEA8FEA03ULL, +0xECCA6A656589650FULL, 0x686903BABAD2BAB9ULL, 0x935E4A2F2FBC2F65ULL, 0xE79D8EC0C027C04EULL, +0x81A160DEDE5FDEBEULL, 0x6C38FC1C1C701CE0ULL, 0x2EE746FDFDD3FDBBULL, 0x649A1F4D4D294D52ULL, +0xE0397692927292E4ULL, 0xBCEAFA7575C9758FULL, 0x1E0C360606180630ULL, 0x9809AE8A8A128A24ULL, +0x40794BB2B2F2B2F9ULL, 0x59D185E6E6BFE663ULL, 0x361C7E0E0E380E70ULL, 0x633EE71F1F7C1FF8ULL, +0xF7C4556262956237ULL, 0xA3B53AD4D477D4EEULL, 0x324D81A8A89AA829ULL, 0xF4315296966296C4ULL, +0x3AEF62F9F9C3F99BULL, 0xF697A3C5C533C566ULL, 0xB14A102525942535ULL, 0x20B2AB59597959F2ULL, +0xAE15D084842A8454ULL, 0xA7E4C57272D572B7ULL, 0xDD72EC3939E439D5ULL, 0x6198164C4C2D4C5AULL, +0x3BBC945E5E655ECAULL, 0x85F09F7878FD78E7ULL, 0xD870E53838E038DDULL, 0x8605988C8C0A8C14ULL, +0xB2BF17D1D163D1C6ULL, 0x0B57E4A5A5AEA541ULL, 0x4DD9A1E2E2AFE243ULL, 0xF8C24E616199612FULL, +0x457B42B3B3F6B3F1ULL, 0xA542342121842115ULL, 0xD625089C9C4A9C94ULL, 0x663CEE1E1E781EF0ULL, +0x5286614343114322ULL, 0xFC93B1C7C73BC776ULL, 0x2BE54FFCFCD7FCB3ULL, 0x1408240404100420ULL, +0x08A2E351515951B2ULL, 0xC72F2599995E99BCULL, 0xC4DA226D6DA96D4FULL, 0x391A650D0D340D68ULL, +0x35E979FAFACFFA83ULL, 0x84A369DFDF5BDFB6ULL, 0x9BFCA97E7EE57ED7ULL, 0xB44819242490243DULL, +0xD776FE3B3BEC3BC5ULL, 0x3D4B9AABAB96AB31ULL, 0xD181F0CECE1FCE3EULL, 0x5522991111441188ULL, +0x8903838F8F068F0CULL, 0x6B9C044E4E254E4AULL, 0x517366B7B7E6B7D1ULL, 0x60CBE0EBEB8BEB0BULL, +0xCC78C13C3CF03CFDULL, 0xBF1FFD81813E817CULL, 0xFE354094946A94D4ULL, 0x0CF31CF7F7FBF7EBULL, +0x676F18B9B9DEB9A1ULL, 0x5F268B13134C1398ULL, 0x9C58512C2CB02C7DULL, 0xB8BB05D3D36BD3D6ULL, +0x5CD38CE7E7BBE76BULL, 0xCBDC396E6EA56E57ULL, 0xF395AAC4C437C46EULL, 0x0F061B03030C0318ULL, +0x13ACDC565645568AULL, 0x49885E44440D441AULL, 0x9EFEA07F7FE17FDFULL, 0x374F88A9A99EA921ULL, +0x8254672A2AA82A4DULL, 0x6D6B0ABBBBD6BBB1ULL, 0xE29F87C1C123C146ULL, 0x02A6F153535153A2ULL, +0x8BA572DCDC57DCAEULL, 0x2716530B0B2C0B58ULL, 0xD327019D9D4E9D9CULL, 0xC1D82B6C6CAD6C47ULL, +0xF562A43131C43195ULL, 0xB9E8F37474CD7487ULL, 0x09F115F6F6FFF6E3ULL, 0x438C4C464605460AULL, +0x2645A5ACAC8AAC09ULL, 0x970FB589891E893CULL, 0x4428B414145014A0ULL, 0x42DFBAE1E1A3E15BULL, +0x4E2CA616165816B0ULL, 0xD274F73A3AE83ACDULL, 0xD0D2066969B9696FULL, 0x2D12410909240948ULL, +0xADE0D77070DD70A7ULL, 0x54716FB6B6E2B6D9ULL, 0xB7BD1ED0D067D0CEULL, 0x7EC7D6EDED93ED3BULL, +0xDB85E2CCCC17CC2EULL, 0x578468424215422AULL, 0xC22D2C98985A98B4ULL, 0x0E55EDA4A4AAA449ULL, +0x8850752828A0285DULL, 0x31B8865C5C6D5CDAULL, 0x3FED6BF8F8C7F893ULL, 0xA411C28686228644ULL }; + +const u64bit Whirlpool::C4[256] = { +0xC07830D818186018ULL, 0x05AF462623238C23ULL, 0x7EF991B8C6C63FC6ULL, 0x136FCDFBE8E887E8ULL, +0x4CA113CB87872687ULL, 0xA9626D11B8B8DAB8ULL, 0x0805020901010401ULL, 0x426E9E0D4F4F214FULL, +0xADEE6C9B3636D836ULL, 0x590451FFA6A6A2A6ULL, 0xDEBDB90CD2D26FD2ULL, 0xFB06F70EF5F5F3F5ULL, +0xEF80F2967979F979ULL, 0x5FCEDE306F6FA16FULL, 0xFCEF3F6D91917E91ULL, 0xAA07A4F852525552ULL, +0x27FDC04760609D60ULL, 0x89766535BCBCCABCULL, 0xACCD2B379B9B569BULL, 0x048C018A8E8E028EULL, +0x71155BD2A3A3B6A3ULL, 0x603C186C0C0C300CULL, 0xFF8AF6847B7BF17BULL, 0xB5E16A803535D435ULL, +0xE8693AF51D1D741DULL, 0x5347DDB3E0E0A7E0ULL, 0xF6ACB321D7D77BD7ULL, 0x5EED999CC2C22FC2ULL, +0x6D965C432E2EB82EULL, 0x627A96294B4B314BULL, 0xA321E15DFEFEDFFEULL, 0x8216AED557574157ULL, +0xA8412ABD15155415ULL, 0x9FB6EEE87777C177ULL, 0xA5EB6E923737DC37ULL, 0x7B56D79EE5E5B3E5ULL, +0x8CD923139F9F469FULL, 0xD317FD23F0F0E7F0ULL, 0x6A7F94204A4A354AULL, 0x9E95A944DADA4FDAULL, +0xFA25B0A258587D58ULL, 0x06CA8FCFC9C903C9ULL, 0x558D527C2929A429ULL, 0x5022145A0A0A280AULL, +0xE14F7F50B1B1FEB1ULL, 0x691A5DC9A0A0BAA0ULL, 0x7FDAD6146B6BB16BULL, 0x5CAB17D985852E85ULL, +0x8173673CBDBDCEBDULL, 0xD234BA8F5D5D695DULL, 0x8050209010104010ULL, 0xF303F507F4F4F7F4ULL, +0x16C08BDDCBCB0BCBULL, 0xEDC67CD33E3EF83EULL, 0x28110A2D05051405ULL, 0x1FE6CE7867678167ULL, +0x7353D597E4E4B7E4ULL, 0x25BB4E0227279C27ULL, 0x3258827341411941ULL, 0x2C9D0BA78B8B168BULL, +0x510153F6A7A7A6A7ULL, 0xCF94FAB27D7DE97DULL, 0xDCFB374995956E95ULL, 0x8E9FAD56D8D847D8ULL, +0x8B30EB70FBFBCBFBULL, 0x2371C1CDEEEE9FEEULL, 0xC791F8BB7C7CED7CULL, 0x17E3CC7166668566ULL, +0xA68EA77BDDDD53DDULL, 0xB84B2EAF17175C17ULL, 0x02468E4547470147ULL, 0x84DC211A9E9E429EULL, +0x1EC589D4CACA0FCAULL, 0x75995A582D2DB42DULL, 0x9179632EBFBFC6BFULL, 0x381B0E3F07071C07ULL, +0x012347ACADAD8EADULL, 0xEA2FB4B05A5A755AULL, 0x6CB51BEF83833683ULL, 0x85FF66B63333CC33ULL, +0x3FF2C65C63639163ULL, 0x100A041202020802ULL, 0x39384993AAAA92AAULL, 0xAFA8E2DE7171D971ULL, +0x0ECF8DC6C8C807C8ULL, 0xC87D32D119196419ULL, 0x7270923B49493949ULL, 0x869AAF5FD9D943D9ULL, +0xC31DF931F2F2EFF2ULL, 0x4B48DBA8E3E3ABE3ULL, 0xE22AB6B95B5B715BULL, 0x34920DBC88881A88ULL, +0xA4C8293E9A9A529AULL, 0x2DBE4C0B26269826ULL, 0x8DFA64BF3232C832ULL, 0xE94A7D59B0B0FAB0ULL, +0x1B6ACFF2E9E983E9ULL, 0x78331E770F0F3C0FULL, 0xE6A6B733D5D573D5ULL, 0x74BA1DF480803A80ULL, +0x997C6127BEBEC2BEULL, 0x26DE87EBCDCD13CDULL, 0xBDE468893434D034ULL, 0x7A75903248483D48ULL, +0xAB24E354FFFFDBFFULL, 0xF78FF48D7A7AF57AULL, 0xF4EA3D6490907A90ULL, 0xC23EBE9D5F5F615FULL, +0x1DA0403D20208020ULL, 0x67D5D00F6868BD68ULL, 0xD07234CA1A1A681AULL, 0x192C41B7AEAE82AEULL, +0xC95E757DB4B4EAB4ULL, 0x9A19A8CE54544D54ULL, 0xECE53B7F93937693ULL, 0x0DAA442F22228822ULL, +0x07E9C86364648D64ULL, 0xDB12FF2AF1F1E3F1ULL, 0xBFA2E6CC7373D173ULL, 0x905A248212124812ULL, +0x3A5D807A40401D40ULL, 0x4028104808082008ULL, 0x56E89B95C3C32BC3ULL, 0x337BC5DFECEC97ECULL, +0x9690AB4DDBDB4BDBULL, 0x611F5FC0A1A1BEA1ULL, 0x1C8307918D8D0E8DULL, 0xF5C97AC83D3DF43DULL, +0xCCF1335B97976697ULL, 0x0000000000000000ULL, 0x36D483F9CFCF1BCFULL, 0x4587566E2B2BAC2BULL, +0x97B3ECE17676C576ULL, 0x64B019E682823282ULL, 0xFEA9B128D6D67FD6ULL, 0xD87736C31B1B6C1BULL, +0xC15B7774B5B5EEB5ULL, 0x112943BEAFAF86AFULL, 0x77DFD41D6A6AB56AULL, 0xBA0DA0EA50505D50ULL, +0x124C8A5745450945ULL, 0xCB18FB38F3F3EBF3ULL, 0x9DF060AD3030C030ULL, 0x2B74C3C4EFEF9BEFULL, +0xE5C37EDA3F3FFC3FULL, 0x921CAAC755554955ULL, 0x791059DBA2A2B2A2ULL, 0x0365C9E9EAEA8FEAULL, +0x0FECCA6A65658965ULL, 0xB9686903BABAD2BAULL, 0x65935E4A2F2FBC2FULL, 0x4EE79D8EC0C027C0ULL, +0xBE81A160DEDE5FDEULL, 0xE06C38FC1C1C701CULL, 0xBB2EE746FDFDD3FDULL, 0x52649A1F4D4D294DULL, +0xE4E0397692927292ULL, 0x8FBCEAFA7575C975ULL, 0x301E0C3606061806ULL, 0x249809AE8A8A128AULL, +0xF940794BB2B2F2B2ULL, 0x6359D185E6E6BFE6ULL, 0x70361C7E0E0E380EULL, 0xF8633EE71F1F7C1FULL, +0x37F7C45562629562ULL, 0xEEA3B53AD4D477D4ULL, 0x29324D81A8A89AA8ULL, 0xC4F4315296966296ULL, +0x9B3AEF62F9F9C3F9ULL, 0x66F697A3C5C533C5ULL, 0x35B14A1025259425ULL, 0xF220B2AB59597959ULL, +0x54AE15D084842A84ULL, 0xB7A7E4C57272D572ULL, 0xD5DD72EC3939E439ULL, 0x5A6198164C4C2D4CULL, +0xCA3BBC945E5E655EULL, 0xE785F09F7878FD78ULL, 0xDDD870E53838E038ULL, 0x148605988C8C0A8CULL, +0xC6B2BF17D1D163D1ULL, 0x410B57E4A5A5AEA5ULL, 0x434DD9A1E2E2AFE2ULL, 0x2FF8C24E61619961ULL, +0xF1457B42B3B3F6B3ULL, 0x15A5423421218421ULL, 0x94D625089C9C4A9CULL, 0xF0663CEE1E1E781EULL, +0x2252866143431143ULL, 0x76FC93B1C7C73BC7ULL, 0xB32BE54FFCFCD7FCULL, 0x2014082404041004ULL, +0xB208A2E351515951ULL, 0xBCC72F2599995E99ULL, 0x4FC4DA226D6DA96DULL, 0x68391A650D0D340DULL, +0x8335E979FAFACFFAULL, 0xB684A369DFDF5BDFULL, 0xD79BFCA97E7EE57EULL, 0x3DB4481924249024ULL, +0xC5D776FE3B3BEC3BULL, 0x313D4B9AABAB96ABULL, 0x3ED181F0CECE1FCEULL, 0x8855229911114411ULL, +0x0C8903838F8F068FULL, 0x4A6B9C044E4E254EULL, 0xD1517366B7B7E6B7ULL, 0x0B60CBE0EBEB8BEBULL, +0xFDCC78C13C3CF03CULL, 0x7CBF1FFD81813E81ULL, 0xD4FE354094946A94ULL, 0xEB0CF31CF7F7FBF7ULL, +0xA1676F18B9B9DEB9ULL, 0x985F268B13134C13ULL, 0x7D9C58512C2CB02CULL, 0xD6B8BB05D3D36BD3ULL, +0x6B5CD38CE7E7BBE7ULL, 0x57CBDC396E6EA56EULL, 0x6EF395AAC4C437C4ULL, 0x180F061B03030C03ULL, +0x8A13ACDC56564556ULL, 0x1A49885E44440D44ULL, 0xDF9EFEA07F7FE17FULL, 0x21374F88A9A99EA9ULL, +0x4D8254672A2AA82AULL, 0xB16D6B0ABBBBD6BBULL, 0x46E29F87C1C123C1ULL, 0xA202A6F153535153ULL, +0xAE8BA572DCDC57DCULL, 0x582716530B0B2C0BULL, 0x9CD327019D9D4E9DULL, 0x47C1D82B6C6CAD6CULL, +0x95F562A43131C431ULL, 0x87B9E8F37474CD74ULL, 0xE309F115F6F6FFF6ULL, 0x0A438C4C46460546ULL, +0x092645A5ACAC8AACULL, 0x3C970FB589891E89ULL, 0xA04428B414145014ULL, 0x5B42DFBAE1E1A3E1ULL, +0xB04E2CA616165816ULL, 0xCDD274F73A3AE83AULL, 0x6FD0D2066969B969ULL, 0x482D124109092409ULL, +0xA7ADE0D77070DD70ULL, 0xD954716FB6B6E2B6ULL, 0xCEB7BD1ED0D067D0ULL, 0x3B7EC7D6EDED93EDULL, +0x2EDB85E2CCCC17CCULL, 0x2A57846842421542ULL, 0xB4C22D2C98985A98ULL, 0x490E55EDA4A4AAA4ULL, +0x5D8850752828A028ULL, 0xDA31B8865C5C6D5CULL, 0x933FED6BF8F8C7F8ULL, 0x44A411C286862286ULL }; + +const u64bit Whirlpool::C5[256] = { +0x18C07830D8181860ULL, 0x2305AF462623238CULL, 0xC67EF991B8C6C63FULL, 0xE8136FCDFBE8E887ULL, +0x874CA113CB878726ULL, 0xB8A9626D11B8B8DAULL, 0x0108050209010104ULL, 0x4F426E9E0D4F4F21ULL, +0x36ADEE6C9B3636D8ULL, 0xA6590451FFA6A6A2ULL, 0xD2DEBDB90CD2D26FULL, 0xF5FB06F70EF5F5F3ULL, +0x79EF80F2967979F9ULL, 0x6F5FCEDE306F6FA1ULL, 0x91FCEF3F6D91917EULL, 0x52AA07A4F8525255ULL, +0x6027FDC04760609DULL, 0xBC89766535BCBCCAULL, 0x9BACCD2B379B9B56ULL, 0x8E048C018A8E8E02ULL, +0xA371155BD2A3A3B6ULL, 0x0C603C186C0C0C30ULL, 0x7BFF8AF6847B7BF1ULL, 0x35B5E16A803535D4ULL, +0x1DE8693AF51D1D74ULL, 0xE05347DDB3E0E0A7ULL, 0xD7F6ACB321D7D77BULL, 0xC25EED999CC2C22FULL, +0x2E6D965C432E2EB8ULL, 0x4B627A96294B4B31ULL, 0xFEA321E15DFEFEDFULL, 0x578216AED5575741ULL, +0x15A8412ABD151554ULL, 0x779FB6EEE87777C1ULL, 0x37A5EB6E923737DCULL, 0xE57B56D79EE5E5B3ULL, +0x9F8CD923139F9F46ULL, 0xF0D317FD23F0F0E7ULL, 0x4A6A7F94204A4A35ULL, 0xDA9E95A944DADA4FULL, +0x58FA25B0A258587DULL, 0xC906CA8FCFC9C903ULL, 0x29558D527C2929A4ULL, 0x0A5022145A0A0A28ULL, +0xB1E14F7F50B1B1FEULL, 0xA0691A5DC9A0A0BAULL, 0x6B7FDAD6146B6BB1ULL, 0x855CAB17D985852EULL, +0xBD8173673CBDBDCEULL, 0x5DD234BA8F5D5D69ULL, 0x1080502090101040ULL, 0xF4F303F507F4F4F7ULL, +0xCB16C08BDDCBCB0BULL, 0x3EEDC67CD33E3EF8ULL, 0x0528110A2D050514ULL, 0x671FE6CE78676781ULL, +0xE47353D597E4E4B7ULL, 0x2725BB4E0227279CULL, 0x4132588273414119ULL, 0x8B2C9D0BA78B8B16ULL, +0xA7510153F6A7A7A6ULL, 0x7DCF94FAB27D7DE9ULL, 0x95DCFB374995956EULL, 0xD88E9FAD56D8D847ULL, +0xFB8B30EB70FBFBCBULL, 0xEE2371C1CDEEEE9FULL, 0x7CC791F8BB7C7CEDULL, 0x6617E3CC71666685ULL, +0xDDA68EA77BDDDD53ULL, 0x17B84B2EAF17175CULL, 0x4702468E45474701ULL, 0x9E84DC211A9E9E42ULL, +0xCA1EC589D4CACA0FULL, 0x2D75995A582D2DB4ULL, 0xBF9179632EBFBFC6ULL, 0x07381B0E3F07071CULL, +0xAD012347ACADAD8EULL, 0x5AEA2FB4B05A5A75ULL, 0x836CB51BEF838336ULL, 0x3385FF66B63333CCULL, +0x633FF2C65C636391ULL, 0x02100A0412020208ULL, 0xAA39384993AAAA92ULL, 0x71AFA8E2DE7171D9ULL, +0xC80ECF8DC6C8C807ULL, 0x19C87D32D1191964ULL, 0x497270923B494939ULL, 0xD9869AAF5FD9D943ULL, +0xF2C31DF931F2F2EFULL, 0xE34B48DBA8E3E3ABULL, 0x5BE22AB6B95B5B71ULL, 0x8834920DBC88881AULL, +0x9AA4C8293E9A9A52ULL, 0x262DBE4C0B262698ULL, 0x328DFA64BF3232C8ULL, 0xB0E94A7D59B0B0FAULL, +0xE91B6ACFF2E9E983ULL, 0x0F78331E770F0F3CULL, 0xD5E6A6B733D5D573ULL, 0x8074BA1DF480803AULL, +0xBE997C6127BEBEC2ULL, 0xCD26DE87EBCDCD13ULL, 0x34BDE468893434D0ULL, 0x487A75903248483DULL, +0xFFAB24E354FFFFDBULL, 0x7AF78FF48D7A7AF5ULL, 0x90F4EA3D6490907AULL, 0x5FC23EBE9D5F5F61ULL, +0x201DA0403D202080ULL, 0x6867D5D00F6868BDULL, 0x1AD07234CA1A1A68ULL, 0xAE192C41B7AEAE82ULL, +0xB4C95E757DB4B4EAULL, 0x549A19A8CE54544DULL, 0x93ECE53B7F939376ULL, 0x220DAA442F222288ULL, +0x6407E9C86364648DULL, 0xF1DB12FF2AF1F1E3ULL, 0x73BFA2E6CC7373D1ULL, 0x12905A2482121248ULL, +0x403A5D807A40401DULL, 0x0840281048080820ULL, 0xC356E89B95C3C32BULL, 0xEC337BC5DFECEC97ULL, +0xDB9690AB4DDBDB4BULL, 0xA1611F5FC0A1A1BEULL, 0x8D1C8307918D8D0EULL, 0x3DF5C97AC83D3DF4ULL, +0x97CCF1335B979766ULL, 0x0000000000000000ULL, 0xCF36D483F9CFCF1BULL, 0x2B4587566E2B2BACULL, +0x7697B3ECE17676C5ULL, 0x8264B019E6828232ULL, 0xD6FEA9B128D6D67FULL, 0x1BD87736C31B1B6CULL, +0xB5C15B7774B5B5EEULL, 0xAF112943BEAFAF86ULL, 0x6A77DFD41D6A6AB5ULL, 0x50BA0DA0EA50505DULL, +0x45124C8A57454509ULL, 0xF3CB18FB38F3F3EBULL, 0x309DF060AD3030C0ULL, 0xEF2B74C3C4EFEF9BULL, +0x3FE5C37EDA3F3FFCULL, 0x55921CAAC7555549ULL, 0xA2791059DBA2A2B2ULL, 0xEA0365C9E9EAEA8FULL, +0x650FECCA6A656589ULL, 0xBAB9686903BABAD2ULL, 0x2F65935E4A2F2FBCULL, 0xC04EE79D8EC0C027ULL, +0xDEBE81A160DEDE5FULL, 0x1CE06C38FC1C1C70ULL, 0xFDBB2EE746FDFDD3ULL, 0x4D52649A1F4D4D29ULL, +0x92E4E03976929272ULL, 0x758FBCEAFA7575C9ULL, 0x06301E0C36060618ULL, 0x8A249809AE8A8A12ULL, +0xB2F940794BB2B2F2ULL, 0xE66359D185E6E6BFULL, 0x0E70361C7E0E0E38ULL, 0x1FF8633EE71F1F7CULL, +0x6237F7C455626295ULL, 0xD4EEA3B53AD4D477ULL, 0xA829324D81A8A89AULL, 0x96C4F43152969662ULL, +0xF99B3AEF62F9F9C3ULL, 0xC566F697A3C5C533ULL, 0x2535B14A10252594ULL, 0x59F220B2AB595979ULL, +0x8454AE15D084842AULL, 0x72B7A7E4C57272D5ULL, 0x39D5DD72EC3939E4ULL, 0x4C5A6198164C4C2DULL, +0x5ECA3BBC945E5E65ULL, 0x78E785F09F7878FDULL, 0x38DDD870E53838E0ULL, 0x8C148605988C8C0AULL, +0xD1C6B2BF17D1D163ULL, 0xA5410B57E4A5A5AEULL, 0xE2434DD9A1E2E2AFULL, 0x612FF8C24E616199ULL, +0xB3F1457B42B3B3F6ULL, 0x2115A54234212184ULL, 0x9C94D625089C9C4AULL, 0x1EF0663CEE1E1E78ULL, +0x4322528661434311ULL, 0xC776FC93B1C7C73BULL, 0xFCB32BE54FFCFCD7ULL, 0x0420140824040410ULL, +0x51B208A2E3515159ULL, 0x99BCC72F2599995EULL, 0x6D4FC4DA226D6DA9ULL, 0x0D68391A650D0D34ULL, +0xFA8335E979FAFACFULL, 0xDFB684A369DFDF5BULL, 0x7ED79BFCA97E7EE5ULL, 0x243DB44819242490ULL, +0x3BC5D776FE3B3BECULL, 0xAB313D4B9AABAB96ULL, 0xCE3ED181F0CECE1FULL, 0x1188552299111144ULL, +0x8F0C8903838F8F06ULL, 0x4E4A6B9C044E4E25ULL, 0xB7D1517366B7B7E6ULL, 0xEB0B60CBE0EBEB8BULL, +0x3CFDCC78C13C3CF0ULL, 0x817CBF1FFD81813EULL, 0x94D4FE354094946AULL, 0xF7EB0CF31CF7F7FBULL, +0xB9A1676F18B9B9DEULL, 0x13985F268B13134CULL, 0x2C7D9C58512C2CB0ULL, 0xD3D6B8BB05D3D36BULL, +0xE76B5CD38CE7E7BBULL, 0x6E57CBDC396E6EA5ULL, 0xC46EF395AAC4C437ULL, 0x03180F061B03030CULL, +0x568A13ACDC565645ULL, 0x441A49885E44440DULL, 0x7FDF9EFEA07F7FE1ULL, 0xA921374F88A9A99EULL, +0x2A4D8254672A2AA8ULL, 0xBBB16D6B0ABBBBD6ULL, 0xC146E29F87C1C123ULL, 0x53A202A6F1535351ULL, +0xDCAE8BA572DCDC57ULL, 0x0B582716530B0B2CULL, 0x9D9CD327019D9D4EULL, 0x6C47C1D82B6C6CADULL, +0x3195F562A43131C4ULL, 0x7487B9E8F37474CDULL, 0xF6E309F115F6F6FFULL, 0x460A438C4C464605ULL, +0xAC092645A5ACAC8AULL, 0x893C970FB589891EULL, 0x14A04428B4141450ULL, 0xE15B42DFBAE1E1A3ULL, +0x16B04E2CA6161658ULL, 0x3ACDD274F73A3AE8ULL, 0x696FD0D2066969B9ULL, 0x09482D1241090924ULL, +0x70A7ADE0D77070DDULL, 0xB6D954716FB6B6E2ULL, 0xD0CEB7BD1ED0D067ULL, 0xED3B7EC7D6EDED93ULL, +0xCC2EDB85E2CCCC17ULL, 0x422A578468424215ULL, 0x98B4C22D2C98985AULL, 0xA4490E55EDA4A4AAULL, +0x285D8850752828A0ULL, 0x5CDA31B8865C5C6DULL, 0xF8933FED6BF8F8C7ULL, 0x8644A411C2868622ULL }; + +const u64bit Whirlpool::C6[256] = { +0x6018C07830D81818ULL, 0x8C2305AF46262323ULL, 0x3FC67EF991B8C6C6ULL, 0x87E8136FCDFBE8E8ULL, +0x26874CA113CB8787ULL, 0xDAB8A9626D11B8B8ULL, 0x0401080502090101ULL, 0x214F426E9E0D4F4FULL, +0xD836ADEE6C9B3636ULL, 0xA2A6590451FFA6A6ULL, 0x6FD2DEBDB90CD2D2ULL, 0xF3F5FB06F70EF5F5ULL, +0xF979EF80F2967979ULL, 0xA16F5FCEDE306F6FULL, 0x7E91FCEF3F6D9191ULL, 0x5552AA07A4F85252ULL, +0x9D6027FDC0476060ULL, 0xCABC89766535BCBCULL, 0x569BACCD2B379B9BULL, 0x028E048C018A8E8EULL, +0xB6A371155BD2A3A3ULL, 0x300C603C186C0C0CULL, 0xF17BFF8AF6847B7BULL, 0xD435B5E16A803535ULL, +0x741DE8693AF51D1DULL, 0xA7E05347DDB3E0E0ULL, 0x7BD7F6ACB321D7D7ULL, 0x2FC25EED999CC2C2ULL, +0xB82E6D965C432E2EULL, 0x314B627A96294B4BULL, 0xDFFEA321E15DFEFEULL, 0x41578216AED55757ULL, +0x5415A8412ABD1515ULL, 0xC1779FB6EEE87777ULL, 0xDC37A5EB6E923737ULL, 0xB3E57B56D79EE5E5ULL, +0x469F8CD923139F9FULL, 0xE7F0D317FD23F0F0ULL, 0x354A6A7F94204A4AULL, 0x4FDA9E95A944DADAULL, +0x7D58FA25B0A25858ULL, 0x03C906CA8FCFC9C9ULL, 0xA429558D527C2929ULL, 0x280A5022145A0A0AULL, +0xFEB1E14F7F50B1B1ULL, 0xBAA0691A5DC9A0A0ULL, 0xB16B7FDAD6146B6BULL, 0x2E855CAB17D98585ULL, +0xCEBD8173673CBDBDULL, 0x695DD234BA8F5D5DULL, 0x4010805020901010ULL, 0xF7F4F303F507F4F4ULL, +0x0BCB16C08BDDCBCBULL, 0xF83EEDC67CD33E3EULL, 0x140528110A2D0505ULL, 0x81671FE6CE786767ULL, +0xB7E47353D597E4E4ULL, 0x9C2725BB4E022727ULL, 0x1941325882734141ULL, 0x168B2C9D0BA78B8BULL, +0xA6A7510153F6A7A7ULL, 0xE97DCF94FAB27D7DULL, 0x6E95DCFB37499595ULL, 0x47D88E9FAD56D8D8ULL, +0xCBFB8B30EB70FBFBULL, 0x9FEE2371C1CDEEEEULL, 0xED7CC791F8BB7C7CULL, 0x856617E3CC716666ULL, +0x53DDA68EA77BDDDDULL, 0x5C17B84B2EAF1717ULL, 0x014702468E454747ULL, 0x429E84DC211A9E9EULL, +0x0FCA1EC589D4CACAULL, 0xB42D75995A582D2DULL, 0xC6BF9179632EBFBFULL, 0x1C07381B0E3F0707ULL, +0x8EAD012347ACADADULL, 0x755AEA2FB4B05A5AULL, 0x36836CB51BEF8383ULL, 0xCC3385FF66B63333ULL, +0x91633FF2C65C6363ULL, 0x0802100A04120202ULL, 0x92AA39384993AAAAULL, 0xD971AFA8E2DE7171ULL, +0x07C80ECF8DC6C8C8ULL, 0x6419C87D32D11919ULL, 0x39497270923B4949ULL, 0x43D9869AAF5FD9D9ULL, +0xEFF2C31DF931F2F2ULL, 0xABE34B48DBA8E3E3ULL, 0x715BE22AB6B95B5BULL, 0x1A8834920DBC8888ULL, +0x529AA4C8293E9A9AULL, 0x98262DBE4C0B2626ULL, 0xC8328DFA64BF3232ULL, 0xFAB0E94A7D59B0B0ULL, +0x83E91B6ACFF2E9E9ULL, 0x3C0F78331E770F0FULL, 0x73D5E6A6B733D5D5ULL, 0x3A8074BA1DF48080ULL, +0xC2BE997C6127BEBEULL, 0x13CD26DE87EBCDCDULL, 0xD034BDE468893434ULL, 0x3D487A7590324848ULL, +0xDBFFAB24E354FFFFULL, 0xF57AF78FF48D7A7AULL, 0x7A90F4EA3D649090ULL, 0x615FC23EBE9D5F5FULL, +0x80201DA0403D2020ULL, 0xBD6867D5D00F6868ULL, 0x681AD07234CA1A1AULL, 0x82AE192C41B7AEAEULL, +0xEAB4C95E757DB4B4ULL, 0x4D549A19A8CE5454ULL, 0x7693ECE53B7F9393ULL, 0x88220DAA442F2222ULL, +0x8D6407E9C8636464ULL, 0xE3F1DB12FF2AF1F1ULL, 0xD173BFA2E6CC7373ULL, 0x4812905A24821212ULL, +0x1D403A5D807A4040ULL, 0x2008402810480808ULL, 0x2BC356E89B95C3C3ULL, 0x97EC337BC5DFECECULL, +0x4BDB9690AB4DDBDBULL, 0xBEA1611F5FC0A1A1ULL, 0x0E8D1C8307918D8DULL, 0xF43DF5C97AC83D3DULL, +0x6697CCF1335B9797ULL, 0x0000000000000000ULL, 0x1BCF36D483F9CFCFULL, 0xAC2B4587566E2B2BULL, +0xC57697B3ECE17676ULL, 0x328264B019E68282ULL, 0x7FD6FEA9B128D6D6ULL, 0x6C1BD87736C31B1BULL, +0xEEB5C15B7774B5B5ULL, 0x86AF112943BEAFAFULL, 0xB56A77DFD41D6A6AULL, 0x5D50BA0DA0EA5050ULL, +0x0945124C8A574545ULL, 0xEBF3CB18FB38F3F3ULL, 0xC0309DF060AD3030ULL, 0x9BEF2B74C3C4EFEFULL, +0xFC3FE5C37EDA3F3FULL, 0x4955921CAAC75555ULL, 0xB2A2791059DBA2A2ULL, 0x8FEA0365C9E9EAEAULL, +0x89650FECCA6A6565ULL, 0xD2BAB9686903BABAULL, 0xBC2F65935E4A2F2FULL, 0x27C04EE79D8EC0C0ULL, +0x5FDEBE81A160DEDEULL, 0x701CE06C38FC1C1CULL, 0xD3FDBB2EE746FDFDULL, 0x294D52649A1F4D4DULL, +0x7292E4E039769292ULL, 0xC9758FBCEAFA7575ULL, 0x1806301E0C360606ULL, 0x128A249809AE8A8AULL, +0xF2B2F940794BB2B2ULL, 0xBFE66359D185E6E6ULL, 0x380E70361C7E0E0EULL, 0x7C1FF8633EE71F1FULL, +0x956237F7C4556262ULL, 0x77D4EEA3B53AD4D4ULL, 0x9AA829324D81A8A8ULL, 0x6296C4F431529696ULL, +0xC3F99B3AEF62F9F9ULL, 0x33C566F697A3C5C5ULL, 0x942535B14A102525ULL, 0x7959F220B2AB5959ULL, +0x2A8454AE15D08484ULL, 0xD572B7A7E4C57272ULL, 0xE439D5DD72EC3939ULL, 0x2D4C5A6198164C4CULL, +0x655ECA3BBC945E5EULL, 0xFD78E785F09F7878ULL, 0xE038DDD870E53838ULL, 0x0A8C148605988C8CULL, +0x63D1C6B2BF17D1D1ULL, 0xAEA5410B57E4A5A5ULL, 0xAFE2434DD9A1E2E2ULL, 0x99612FF8C24E6161ULL, +0xF6B3F1457B42B3B3ULL, 0x842115A542342121ULL, 0x4A9C94D625089C9CULL, 0x781EF0663CEE1E1EULL, +0x1143225286614343ULL, 0x3BC776FC93B1C7C7ULL, 0xD7FCB32BE54FFCFCULL, 0x1004201408240404ULL, +0x5951B208A2E35151ULL, 0x5E99BCC72F259999ULL, 0xA96D4FC4DA226D6DULL, 0x340D68391A650D0DULL, +0xCFFA8335E979FAFAULL, 0x5BDFB684A369DFDFULL, 0xE57ED79BFCA97E7EULL, 0x90243DB448192424ULL, +0xEC3BC5D776FE3B3BULL, 0x96AB313D4B9AABABULL, 0x1FCE3ED181F0CECEULL, 0x4411885522991111ULL, +0x068F0C8903838F8FULL, 0x254E4A6B9C044E4EULL, 0xE6B7D1517366B7B7ULL, 0x8BEB0B60CBE0EBEBULL, +0xF03CFDCC78C13C3CULL, 0x3E817CBF1FFD8181ULL, 0x6A94D4FE35409494ULL, 0xFBF7EB0CF31CF7F7ULL, +0xDEB9A1676F18B9B9ULL, 0x4C13985F268B1313ULL, 0xB02C7D9C58512C2CULL, 0x6BD3D6B8BB05D3D3ULL, +0xBBE76B5CD38CE7E7ULL, 0xA56E57CBDC396E6EULL, 0x37C46EF395AAC4C4ULL, 0x0C03180F061B0303ULL, +0x45568A13ACDC5656ULL, 0x0D441A49885E4444ULL, 0xE17FDF9EFEA07F7FULL, 0x9EA921374F88A9A9ULL, +0xA82A4D8254672A2AULL, 0xD6BBB16D6B0ABBBBULL, 0x23C146E29F87C1C1ULL, 0x5153A202A6F15353ULL, +0x57DCAE8BA572DCDCULL, 0x2C0B582716530B0BULL, 0x4E9D9CD327019D9DULL, 0xAD6C47C1D82B6C6CULL, +0xC43195F562A43131ULL, 0xCD7487B9E8F37474ULL, 0xFFF6E309F115F6F6ULL, 0x05460A438C4C4646ULL, +0x8AAC092645A5ACACULL, 0x1E893C970FB58989ULL, 0x5014A04428B41414ULL, 0xA3E15B42DFBAE1E1ULL, +0x5816B04E2CA61616ULL, 0xE83ACDD274F73A3AULL, 0xB9696FD0D2066969ULL, 0x2409482D12410909ULL, +0xDD70A7ADE0D77070ULL, 0xE2B6D954716FB6B6ULL, 0x67D0CEB7BD1ED0D0ULL, 0x93ED3B7EC7D6EDEDULL, +0x17CC2EDB85E2CCCCULL, 0x15422A5784684242ULL, 0x5A98B4C22D2C9898ULL, 0xAAA4490E55EDA4A4ULL, +0xA0285D8850752828ULL, 0x6D5CDA31B8865C5CULL, 0xC7F8933FED6BF8F8ULL, 0x228644A411C28686ULL }; + +const u64bit Whirlpool::C7[256] = { +0x186018C07830D818ULL, 0x238C2305AF462623ULL, 0xC63FC67EF991B8C6ULL, 0xE887E8136FCDFBE8ULL, +0x8726874CA113CB87ULL, 0xB8DAB8A9626D11B8ULL, 0x0104010805020901ULL, 0x4F214F426E9E0D4FULL, +0x36D836ADEE6C9B36ULL, 0xA6A2A6590451FFA6ULL, 0xD26FD2DEBDB90CD2ULL, 0xF5F3F5FB06F70EF5ULL, +0x79F979EF80F29679ULL, 0x6FA16F5FCEDE306FULL, 0x917E91FCEF3F6D91ULL, 0x525552AA07A4F852ULL, +0x609D6027FDC04760ULL, 0xBCCABC89766535BCULL, 0x9B569BACCD2B379BULL, 0x8E028E048C018A8EULL, +0xA3B6A371155BD2A3ULL, 0x0C300C603C186C0CULL, 0x7BF17BFF8AF6847BULL, 0x35D435B5E16A8035ULL, +0x1D741DE8693AF51DULL, 0xE0A7E05347DDB3E0ULL, 0xD77BD7F6ACB321D7ULL, 0xC22FC25EED999CC2ULL, +0x2EB82E6D965C432EULL, 0x4B314B627A96294BULL, 0xFEDFFEA321E15DFEULL, 0x5741578216AED557ULL, +0x155415A8412ABD15ULL, 0x77C1779FB6EEE877ULL, 0x37DC37A5EB6E9237ULL, 0xE5B3E57B56D79EE5ULL, +0x9F469F8CD923139FULL, 0xF0E7F0D317FD23F0ULL, 0x4A354A6A7F94204AULL, 0xDA4FDA9E95A944DAULL, +0x587D58FA25B0A258ULL, 0xC903C906CA8FCFC9ULL, 0x29A429558D527C29ULL, 0x0A280A5022145A0AULL, +0xB1FEB1E14F7F50B1ULL, 0xA0BAA0691A5DC9A0ULL, 0x6BB16B7FDAD6146BULL, 0x852E855CAB17D985ULL, +0xBDCEBD8173673CBDULL, 0x5D695DD234BA8F5DULL, 0x1040108050209010ULL, 0xF4F7F4F303F507F4ULL, +0xCB0BCB16C08BDDCBULL, 0x3EF83EEDC67CD33EULL, 0x05140528110A2D05ULL, 0x6781671FE6CE7867ULL, +0xE4B7E47353D597E4ULL, 0x279C2725BB4E0227ULL, 0x4119413258827341ULL, 0x8B168B2C9D0BA78BULL, +0xA7A6A7510153F6A7ULL, 0x7DE97DCF94FAB27DULL, 0x956E95DCFB374995ULL, 0xD847D88E9FAD56D8ULL, +0xFBCBFB8B30EB70FBULL, 0xEE9FEE2371C1CDEEULL, 0x7CED7CC791F8BB7CULL, 0x66856617E3CC7166ULL, +0xDD53DDA68EA77BDDULL, 0x175C17B84B2EAF17ULL, 0x47014702468E4547ULL, 0x9E429E84DC211A9EULL, +0xCA0FCA1EC589D4CAULL, 0x2DB42D75995A582DULL, 0xBFC6BF9179632EBFULL, 0x071C07381B0E3F07ULL, +0xAD8EAD012347ACADULL, 0x5A755AEA2FB4B05AULL, 0x8336836CB51BEF83ULL, 0x33CC3385FF66B633ULL, +0x6391633FF2C65C63ULL, 0x020802100A041202ULL, 0xAA92AA39384993AAULL, 0x71D971AFA8E2DE71ULL, +0xC807C80ECF8DC6C8ULL, 0x196419C87D32D119ULL, 0x4939497270923B49ULL, 0xD943D9869AAF5FD9ULL, +0xF2EFF2C31DF931F2ULL, 0xE3ABE34B48DBA8E3ULL, 0x5B715BE22AB6B95BULL, 0x881A8834920DBC88ULL, +0x9A529AA4C8293E9AULL, 0x2698262DBE4C0B26ULL, 0x32C8328DFA64BF32ULL, 0xB0FAB0E94A7D59B0ULL, +0xE983E91B6ACFF2E9ULL, 0x0F3C0F78331E770FULL, 0xD573D5E6A6B733D5ULL, 0x803A8074BA1DF480ULL, +0xBEC2BE997C6127BEULL, 0xCD13CD26DE87EBCDULL, 0x34D034BDE4688934ULL, 0x483D487A75903248ULL, +0xFFDBFFAB24E354FFULL, 0x7AF57AF78FF48D7AULL, 0x907A90F4EA3D6490ULL, 0x5F615FC23EBE9D5FULL, +0x2080201DA0403D20ULL, 0x68BD6867D5D00F68ULL, 0x1A681AD07234CA1AULL, 0xAE82AE192C41B7AEULL, +0xB4EAB4C95E757DB4ULL, 0x544D549A19A8CE54ULL, 0x937693ECE53B7F93ULL, 0x2288220DAA442F22ULL, +0x648D6407E9C86364ULL, 0xF1E3F1DB12FF2AF1ULL, 0x73D173BFA2E6CC73ULL, 0x124812905A248212ULL, +0x401D403A5D807A40ULL, 0x0820084028104808ULL, 0xC32BC356E89B95C3ULL, 0xEC97EC337BC5DFECULL, +0xDB4BDB9690AB4DDBULL, 0xA1BEA1611F5FC0A1ULL, 0x8D0E8D1C8307918DULL, 0x3DF43DF5C97AC83DULL, +0x976697CCF1335B97ULL, 0x0000000000000000ULL, 0xCF1BCF36D483F9CFULL, 0x2BAC2B4587566E2BULL, +0x76C57697B3ECE176ULL, 0x82328264B019E682ULL, 0xD67FD6FEA9B128D6ULL, 0x1B6C1BD87736C31BULL, +0xB5EEB5C15B7774B5ULL, 0xAF86AF112943BEAFULL, 0x6AB56A77DFD41D6AULL, 0x505D50BA0DA0EA50ULL, +0x450945124C8A5745ULL, 0xF3EBF3CB18FB38F3ULL, 0x30C0309DF060AD30ULL, 0xEF9BEF2B74C3C4EFULL, +0x3FFC3FE5C37EDA3FULL, 0x554955921CAAC755ULL, 0xA2B2A2791059DBA2ULL, 0xEA8FEA0365C9E9EAULL, +0x6589650FECCA6A65ULL, 0xBAD2BAB9686903BAULL, 0x2FBC2F65935E4A2FULL, 0xC027C04EE79D8EC0ULL, +0xDE5FDEBE81A160DEULL, 0x1C701CE06C38FC1CULL, 0xFDD3FDBB2EE746FDULL, 0x4D294D52649A1F4DULL, +0x927292E4E0397692ULL, 0x75C9758FBCEAFA75ULL, 0x061806301E0C3606ULL, 0x8A128A249809AE8AULL, +0xB2F2B2F940794BB2ULL, 0xE6BFE66359D185E6ULL, 0x0E380E70361C7E0EULL, 0x1F7C1FF8633EE71FULL, +0x62956237F7C45562ULL, 0xD477D4EEA3B53AD4ULL, 0xA89AA829324D81A8ULL, 0x966296C4F4315296ULL, +0xF9C3F99B3AEF62F9ULL, 0xC533C566F697A3C5ULL, 0x25942535B14A1025ULL, 0x597959F220B2AB59ULL, +0x842A8454AE15D084ULL, 0x72D572B7A7E4C572ULL, 0x39E439D5DD72EC39ULL, 0x4C2D4C5A6198164CULL, +0x5E655ECA3BBC945EULL, 0x78FD78E785F09F78ULL, 0x38E038DDD870E538ULL, 0x8C0A8C148605988CULL, +0xD163D1C6B2BF17D1ULL, 0xA5AEA5410B57E4A5ULL, 0xE2AFE2434DD9A1E2ULL, 0x6199612FF8C24E61ULL, +0xB3F6B3F1457B42B3ULL, 0x21842115A5423421ULL, 0x9C4A9C94D625089CULL, 0x1E781EF0663CEE1EULL, +0x4311432252866143ULL, 0xC73BC776FC93B1C7ULL, 0xFCD7FCB32BE54FFCULL, 0x0410042014082404ULL, +0x515951B208A2E351ULL, 0x995E99BCC72F2599ULL, 0x6DA96D4FC4DA226DULL, 0x0D340D68391A650DULL, +0xFACFFA8335E979FAULL, 0xDF5BDFB684A369DFULL, 0x7EE57ED79BFCA97EULL, 0x2490243DB4481924ULL, +0x3BEC3BC5D776FE3BULL, 0xAB96AB313D4B9AABULL, 0xCE1FCE3ED181F0CEULL, 0x1144118855229911ULL, +0x8F068F0C8903838FULL, 0x4E254E4A6B9C044EULL, 0xB7E6B7D1517366B7ULL, 0xEB8BEB0B60CBE0EBULL, +0x3CF03CFDCC78C13CULL, 0x813E817CBF1FFD81ULL, 0x946A94D4FE354094ULL, 0xF7FBF7EB0CF31CF7ULL, +0xB9DEB9A1676F18B9ULL, 0x134C13985F268B13ULL, 0x2CB02C7D9C58512CULL, 0xD36BD3D6B8BB05D3ULL, +0xE7BBE76B5CD38CE7ULL, 0x6EA56E57CBDC396EULL, 0xC437C46EF395AAC4ULL, 0x030C03180F061B03ULL, +0x5645568A13ACDC56ULL, 0x440D441A49885E44ULL, 0x7FE17FDF9EFEA07FULL, 0xA99EA921374F88A9ULL, +0x2AA82A4D8254672AULL, 0xBBD6BBB16D6B0ABBULL, 0xC123C146E29F87C1ULL, 0x535153A202A6F153ULL, +0xDC57DCAE8BA572DCULL, 0x0B2C0B582716530BULL, 0x9D4E9D9CD327019DULL, 0x6CAD6C47C1D82B6CULL, +0x31C43195F562A431ULL, 0x74CD7487B9E8F374ULL, 0xF6FFF6E309F115F6ULL, 0x4605460A438C4C46ULL, +0xAC8AAC092645A5ACULL, 0x891E893C970FB589ULL, 0x145014A04428B414ULL, 0xE1A3E15B42DFBAE1ULL, +0x165816B04E2CA616ULL, 0x3AE83ACDD274F73AULL, 0x69B9696FD0D20669ULL, 0x092409482D124109ULL, +0x70DD70A7ADE0D770ULL, 0xB6E2B6D954716FB6ULL, 0xD067D0CEB7BD1ED0ULL, 0xED93ED3B7EC7D6EDULL, +0xCC17CC2EDB85E2CCULL, 0x4215422A57846842ULL, 0x985A98B4C22D2C98ULL, 0xA4AAA4490E55EDA4ULL, +0x28A0285D88507528ULL, 0x5C6D5CDA31B8865CULL, 0xF8C7F8933FED6BF8ULL, 0x86228644A411C286ULL }; + +} +/* +* Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Whirlpool Compression Function +*/ +void Whirlpool::compress_n(const byte in[], size_t blocks) + { + static const u64bit RC[10] = { + 0x1823C6E887B8014FULL, 0x36A6D2F5796F9152ULL, + 0x60BC9B8EA30C7B35ULL, 0x1DE0D7C22E4BFE57ULL, + 0x157737E59FF04ADAULL, 0x58C9290AB1A06B85ULL, + 0xBD5D10F4CB3E0567ULL, 0xE427418BA77D95D8ULL, + 0xFBEE7C66DD17479EULL, 0xCA2DBF07AD5A8333ULL + }; + + for(size_t i = 0; i != blocks; ++i) + { + load_be(&M[0], in, M.size()); + + u64bit K0, K1, K2, K3, K4, K5, K6, K7; + K0 = digest[0]; K1 = digest[1]; K2 = digest[2]; K3 = digest[3]; + K4 = digest[4]; K5 = digest[5]; K6 = digest[6]; K7 = digest[7]; + + u64bit B0, B1, B2, B3, B4, B5, B6, B7; + B0 = K0 ^ M[0]; B1 = K1 ^ M[1]; B2 = K2 ^ M[2]; B3 = K3 ^ M[3]; + B4 = K4 ^ M[4]; B5 = K5 ^ M[5]; B6 = K6 ^ M[6]; B7 = K7 ^ M[7]; + + for(size_t j = 0; j != 10; ++j) + { + u64bit T0, T1, T2, T3, T4, T5, T6, T7; + T0 = C0[get_byte(0, K0)] ^ C1[get_byte(1, K7)] ^ + C2[get_byte(2, K6)] ^ C3[get_byte(3, K5)] ^ + C4[get_byte(4, K4)] ^ C5[get_byte(5, K3)] ^ + C6[get_byte(6, K2)] ^ C7[get_byte(7, K1)] ^ RC[j]; + T1 = C0[get_byte(0, K1)] ^ C1[get_byte(1, K0)] ^ + C2[get_byte(2, K7)] ^ C3[get_byte(3, K6)] ^ + C4[get_byte(4, K5)] ^ C5[get_byte(5, K4)] ^ + C6[get_byte(6, K3)] ^ C7[get_byte(7, K2)]; + T2 = C0[get_byte(0, K2)] ^ C1[get_byte(1, K1)] ^ + C2[get_byte(2, K0)] ^ C3[get_byte(3, K7)] ^ + C4[get_byte(4, K6)] ^ C5[get_byte(5, K5)] ^ + C6[get_byte(6, K4)] ^ C7[get_byte(7, K3)]; + T3 = C0[get_byte(0, K3)] ^ C1[get_byte(1, K2)] ^ + C2[get_byte(2, K1)] ^ C3[get_byte(3, K0)] ^ + C4[get_byte(4, K7)] ^ C5[get_byte(5, K6)] ^ + C6[get_byte(6, K5)] ^ C7[get_byte(7, K4)]; + T4 = C0[get_byte(0, K4)] ^ C1[get_byte(1, K3)] ^ + C2[get_byte(2, K2)] ^ C3[get_byte(3, K1)] ^ + C4[get_byte(4, K0)] ^ C5[get_byte(5, K7)] ^ + C6[get_byte(6, K6)] ^ C7[get_byte(7, K5)]; + T5 = C0[get_byte(0, K5)] ^ C1[get_byte(1, K4)] ^ + C2[get_byte(2, K3)] ^ C3[get_byte(3, K2)] ^ + C4[get_byte(4, K1)] ^ C5[get_byte(5, K0)] ^ + C6[get_byte(6, K7)] ^ C7[get_byte(7, K6)]; + T6 = C0[get_byte(0, K6)] ^ C1[get_byte(1, K5)] ^ + C2[get_byte(2, K4)] ^ C3[get_byte(3, K3)] ^ + C4[get_byte(4, K2)] ^ C5[get_byte(5, K1)] ^ + C6[get_byte(6, K0)] ^ C7[get_byte(7, K7)]; + T7 = C0[get_byte(0, K7)] ^ C1[get_byte(1, K6)] ^ + C2[get_byte(2, K5)] ^ C3[get_byte(3, K4)] ^ + C4[get_byte(4, K3)] ^ C5[get_byte(5, K2)] ^ + C6[get_byte(6, K1)] ^ C7[get_byte(7, K0)]; + + K0 = T0; K1 = T1; K2 = T2; K3 = T3; + K4 = T4; K5 = T5; K6 = T6; K7 = T7; + + T0 = C0[get_byte(0, B0)] ^ C1[get_byte(1, B7)] ^ + C2[get_byte(2, B6)] ^ C3[get_byte(3, B5)] ^ + C4[get_byte(4, B4)] ^ C5[get_byte(5, B3)] ^ + C6[get_byte(6, B2)] ^ C7[get_byte(7, B1)] ^ K0; + T1 = C0[get_byte(0, B1)] ^ C1[get_byte(1, B0)] ^ + C2[get_byte(2, B7)] ^ C3[get_byte(3, B6)] ^ + C4[get_byte(4, B5)] ^ C5[get_byte(5, B4)] ^ + C6[get_byte(6, B3)] ^ C7[get_byte(7, B2)] ^ K1; + T2 = C0[get_byte(0, B2)] ^ C1[get_byte(1, B1)] ^ + C2[get_byte(2, B0)] ^ C3[get_byte(3, B7)] ^ + C4[get_byte(4, B6)] ^ C5[get_byte(5, B5)] ^ + C6[get_byte(6, B4)] ^ C7[get_byte(7, B3)] ^ K2; + T3 = C0[get_byte(0, B3)] ^ C1[get_byte(1, B2)] ^ + C2[get_byte(2, B1)] ^ C3[get_byte(3, B0)] ^ + C4[get_byte(4, B7)] ^ C5[get_byte(5, B6)] ^ + C6[get_byte(6, B5)] ^ C7[get_byte(7, B4)] ^ K3; + T4 = C0[get_byte(0, B4)] ^ C1[get_byte(1, B3)] ^ + C2[get_byte(2, B2)] ^ C3[get_byte(3, B1)] ^ + C4[get_byte(4, B0)] ^ C5[get_byte(5, B7)] ^ + C6[get_byte(6, B6)] ^ C7[get_byte(7, B5)] ^ K4; + T5 = C0[get_byte(0, B5)] ^ C1[get_byte(1, B4)] ^ + C2[get_byte(2, B3)] ^ C3[get_byte(3, B2)] ^ + C4[get_byte(4, B1)] ^ C5[get_byte(5, B0)] ^ + C6[get_byte(6, B7)] ^ C7[get_byte(7, B6)] ^ K5; + T6 = C0[get_byte(0, B6)] ^ C1[get_byte(1, B5)] ^ + C2[get_byte(2, B4)] ^ C3[get_byte(3, B3)] ^ + C4[get_byte(4, B2)] ^ C5[get_byte(5, B1)] ^ + C6[get_byte(6, B0)] ^ C7[get_byte(7, B7)] ^ K6; + T7 = C0[get_byte(0, B7)] ^ C1[get_byte(1, B6)] ^ + C2[get_byte(2, B5)] ^ C3[get_byte(3, B4)] ^ + C4[get_byte(4, B3)] ^ C5[get_byte(5, B2)] ^ + C6[get_byte(6, B1)] ^ C7[get_byte(7, B0)] ^ K7; + + B0 = T0; B1 = T1; B2 = T2; B3 = T3; + B4 = T4; B5 = T5; B6 = T6; B7 = T7; + } + + digest[0] ^= B0 ^ M[0]; + digest[1] ^= B1 ^ M[1]; + digest[2] ^= B2 ^ M[2]; + digest[3] ^= B3 ^ M[3]; + digest[4] ^= B4 ^ M[4]; + digest[5] ^= B5 ^ M[5]; + digest[6] ^= B6 ^ M[6]; + digest[7] ^= B7 ^ M[7]; + + in += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Whirlpool::copy_out(byte output[]) + { + for(size_t i = 0; i != output_length(); i += 8) + store_be(digest[i/8], output + i); + } + +/* +* Clear memory of sensitive data +*/ +void Whirlpool::clear() + { + MDx_HashFunction::clear(); + zeroise(M); + zeroise(digest); + } + +} +/* +* KDF Base Class +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Derive a key +*/ +SecureVector KDF::derive_key(size_t key_len, + const MemoryRegion& secret, + const std::string& salt) const + { + return derive_key(key_len, &secret[0], secret.size(), + reinterpret_cast(salt.data()), + salt.length()); + } + +/* +* Derive a key +*/ +SecureVector KDF::derive_key(size_t key_len, + const MemoryRegion& secret, + const byte salt[], size_t salt_len) const + { + return derive_key(key_len, &secret[0], secret.size(), + salt, salt_len); + } + +/* +* Derive a key +*/ +SecureVector KDF::derive_key(size_t key_len, + const MemoryRegion& secret, + const MemoryRegion& salt) const + { + return derive_key(key_len, &secret[0], secret.size(), + &salt[0], salt.size()); + } + +/* +* Derive a key +*/ +SecureVector KDF::derive_key(size_t key_len, + const byte secret[], size_t secret_len, + const std::string& salt) const + { + return derive_key(key_len, secret, secret_len, + reinterpret_cast(salt.data()), + salt.length()); + } + +/* +* Derive a key +*/ +SecureVector KDF::derive_key(size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + return derive(key_len, secret, secret_len, salt, salt_len); + } + +} +/* +* KDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* KDF1 Key Derivation Mechanism +*/ +SecureVector KDF1::derive(size_t, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const + { + hash->update(secret, secret_len); + hash->update(P, P_len); + return hash->final(); + } + +} +/* +* KDF2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* KDF2 Key Derivation Mechanism +*/ +SecureVector KDF2::derive(size_t out_len, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const + { + SecureVector output; + u32bit counter = 1; + + while(out_len && counter) + { + hash->update(secret, secret_len); + hash->update_be(counter); + hash->update(P, P_len); + + SecureVector hash_result = hash->final(); + + size_t added = std::min(hash_result.size(), out_len); + output += std::make_pair(&hash_result[0], added); + out_len -= added; + + ++counter; + } + + return output; + } + +} +/* +* MGF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* MGF1 Mask Generation Function +*/ +void MGF1::mask(const byte in[], size_t in_len, byte out[], + size_t out_len) const + { + u32bit counter = 0; + + while(out_len) + { + hash->update(in, in_len); + hash->update_be(counter); + SecureVector buffer = hash->final(); + + size_t xored = std::min(buffer.size(), out_len); + xor_buf(out, &buffer[0], xored); + out += xored; + out_len -= xored; + + ++counter; + } + } + +/* +* MGF1 Constructor +*/ +MGF1::MGF1(HashFunction* h) : hash(h) + { + if(!hash) + throw Invalid_Argument("MGF1 given null hash object"); + } + +/* +* MGF1 Destructor +*/ +MGF1::~MGF1() + { + delete hash; + } + +} +/* +* SSLv3 PRF +* (C) 2004-2006 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* Return the next inner hash +*/ +OctetString next_hash(size_t where, size_t want, + HashFunction& md5, HashFunction& sha1, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) + { + BOTAN_ASSERT(want <= md5.output_length(), "Desired output too large"); + + const byte ASCII_A_CHAR = 0x41; + + for(size_t j = 0; j != where + 1; j++) + sha1.update(static_cast(ASCII_A_CHAR + where)); + sha1.update(secret, secret_len); + sha1.update(seed, seed_len); + SecureVector sha1_hash = sha1.final(); + + md5.update(secret, secret_len); + md5.update(sha1_hash); + SecureVector md5_hash = md5.final(); + + return OctetString(&md5_hash[0], want); + } + +} + +/* +* SSL3 PRF +*/ +SecureVector SSL3_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + if(key_len > 416) + throw Invalid_Argument("SSL3_PRF: Requested key length is too large"); + + MD5 md5; + SHA_160 sha1; + + OctetString output; + + int counter = 0; + while(key_len) + { + const size_t produce = std::min(key_len, md5.output_length()); + + output = output + next_hash(counter++, produce, md5, sha1, + secret, secret_len, seed, seed_len); + + key_len -= produce; + } + + return output.bits_of(); + } + +} +/* +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* TLS PRF P_hash function +*/ +void P_hash(MemoryRegion& output, + MessageAuthenticationCode* mac, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) + { + mac->set_key(secret, secret_len); + + SecureVector A(seed, seed_len); + + size_t offset = 0; + + while(offset != output.size()) + { + const size_t this_block_len = + std::min(mac->output_length(), output.size() - offset); + + A = mac->process(A); + + mac->update(A); + mac->update(seed, seed_len); + SecureVector block = mac->final(); + + xor_buf(&output[offset], &block[0], this_block_len); + offset += this_block_len; + } + } + +} + +/* +* TLS PRF Constructor and Destructor +*/ +TLS_PRF::TLS_PRF() + { + hmac_md5 = new HMAC(new MD5); + hmac_sha1 = new HMAC(new SHA_160); + } + +TLS_PRF::~TLS_PRF() + { + delete hmac_md5; + delete hmac_sha1; + } + +/* +* TLS PRF +*/ +SecureVector TLS_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + SecureVector output(key_len); + + size_t S1_len = (secret_len + 1) / 2, + S2_len = (secret_len + 1) / 2; + const byte* S1 = secret; + const byte* S2 = secret + (secret_len - S2_len); + + P_hash(output, hmac_md5, S1, S1_len, seed, seed_len); + P_hash(output, hmac_sha1, S2, S2_len, seed, seed_len); + + return output; + } + +/* +* TLS v1.2 PRF Constructor and Destructor +*/ +TLS_12_PRF::TLS_12_PRF(MessageAuthenticationCode* mac) : hmac(mac) + { + } + +TLS_12_PRF::~TLS_12_PRF() + { + delete hmac; + } + +SecureVector TLS_12_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const + { + SecureVector output(key_len); + + P_hash(output, hmac, secret, secret_len, seed, seed_len); + + return output; + } + +} +/* +* X9.42 PRF +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Encode an integer as an OCTET STRING +*/ +MemoryVector encode_x942_int(u32bit n) + { + byte n_buf[4] = { 0 }; + store_be(n, n_buf); + return DER_Encoder().encode(n_buf, 4, OCTET_STRING).get_contents(); + } + +} + +/* +* X9.42 PRF +*/ +SecureVector X942_PRF::derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + SHA_160 hash; + const OID kek_algo(key_wrap_oid); + + SecureVector key; + u32bit counter = 1; + + while(key.size() != key_len && counter) + { + hash.update(secret, secret_len); + + hash.update( + DER_Encoder().start_cons(SEQUENCE) + + .start_cons(SEQUENCE) + .encode(kek_algo) + .raw_bytes(encode_x942_int(counter)) + .end_cons() + + .encode_if(salt_len != 0, + DER_Encoder() + .start_explicit(0) + .encode(salt, salt_len, OCTET_STRING) + .end_explicit() + ) + + .start_explicit(2) + .raw_bytes(encode_x942_int(static_cast(8 * key_len))) + .end_explicit() + + .end_cons().get_contents() + ); + + SecureVector digest = hash.final(); + const size_t needed = std::min(digest.size(), key_len - key.size()); + key += std::make_pair(&digest[0], needed); + + ++counter; + } + + return key; + } + +/* +* X9.42 Constructor +*/ +X942_PRF::X942_PRF(const std::string& oid) + { + if(OIDS::have_oid(oid)) + key_wrap_oid = OIDS::lookup(oid).as_string(); + else + key_wrap_oid = oid; + } + +} +/* +* PBKDF/EMSA/EME/KDF/MGF Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_MGF1) +#endif + +#if defined(BOTAN_HAS_EMSA1) +#endif + +#if defined(BOTAN_HAS_EMSA1_BSI) +#endif + +#if defined(BOTAN_HAS_EMSA2) +#endif + +#if defined(BOTAN_HAS_EMSA3) +#endif + +#if defined(BOTAN_HAS_EMSA4) +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) +#endif + +#if defined(BOTAN_HAS_EME1) +#endif + +#if defined(BOTAN_HAS_EME_PKCS1v15) +#endif + +#if defined(BOTAN_HAS_KDF1) +#endif + +#if defined(BOTAN_HAS_KDF2) +#endif + +#if defined(BOTAN_HAS_X942_PRF) +#endif + +#if defined(BOTAN_HAS_SSL_V3_PRF) +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) +#endif + +namespace Botan { + +/* +* Get a PBKDF algorithm by name +*/ +PBKDF* get_pbkdf(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(PBKDF* pbkdf = af.make_pbkdf(algo_spec)) + return pbkdf; + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get an EMSA by name +*/ +EMSA* get_emsa(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + +#if defined(BOTAN_HAS_EMSA_RAW) + if(request.algo_name() == "Raw" && request.arg_count() == 0) + return new EMSA_Raw; +#endif + +#if defined(BOTAN_HAS_EMSA1) + if(request.algo_name() == "EMSA1" && request.arg_count() == 1) + return new EMSA1(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_EMSA1_BSI) + if(request.algo_name() == "EMSA1_BSI" && request.arg_count() == 1) + return new EMSA1_BSI(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_EMSA2) + if(request.algo_name() == "EMSA2" && request.arg_count() == 1) + return new EMSA2(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_EMSA3) + if(request.algo_name() == "EMSA3" && request.arg_count() == 1) + { + if(request.arg(0) == "Raw") + return new EMSA3_Raw; + return new EMSA3(af.make_hash_function(request.arg(0))); + } +#endif + +#if defined(BOTAN_HAS_EMSA4) + if(request.algo_name() == "EMSA4" && request.arg_count_between(1, 3)) + { + // 3 args: Hash, MGF, salt size (MGF is hardcoded MGF1 in Botan) + if(request.arg_count() == 1) + return new EMSA4(af.make_hash_function(request.arg(0))); + + if(request.arg_count() == 2 && request.arg(1) != "MGF1") + return new EMSA4(af.make_hash_function(request.arg(0))); + + if(request.arg_count() == 3) + return new EMSA4(af.make_hash_function(request.arg(0)), + request.arg_as_integer(2, 0)); + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get an EME by name +*/ +EME* get_eme(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(request.algo_name() == "Raw") + return 0; // No padding + +#if defined(BOTAN_HAS_EME_PKCS1v15) + if(request.algo_name() == "PKCS1v15" && request.arg_count() == 0) + return new EME_PKCS1v15; +#endif + +#if defined(BOTAN_HAS_EME1) + if(request.algo_name() == "EME1" && request.arg_count_between(1, 2)) + { + if(request.arg_count() == 1 || + (request.arg_count() == 2 && request.arg(1) == "MGF1")) + { + return new EME1(af.make_hash_function(request.arg(0))); + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get an KDF by name +*/ +KDF* get_kdf(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(request.algo_name() == "Raw") + return 0; // No KDF + +#if defined(BOTAN_HAS_KDF1) + if(request.algo_name() == "KDF1" && request.arg_count() == 1) + return new KDF1(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_KDF2) + if(request.algo_name() == "KDF2" && request.arg_count() == 1) + return new KDF2(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_X942_PRF) + if(request.algo_name() == "X9.42-PRF" && request.arg_count() == 1) + return new X942_PRF(request.arg(0)); // OID +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0) + return new TLS_PRF; +#endif + +#if defined(BOTAN_HAS_SSL_V3_PRF) + if(request.algo_name() == "SSL3-PRF" && request.arg_count() == 0) + return new SSL3_PRF; +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} +/* +* Global PRNG +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_RANDPOOL) +#endif + +#if defined(BOTAN_HAS_HMAC_RNG) +#endif + +#if defined(BOTAN_HAS_X931_RNG) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_FTW) +#endif + +namespace Botan { + +namespace { + +/** +* Add any known entropy sources to this RNG +*/ +void add_entropy_sources(RandomNumberGenerator* rng) + { +#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER) + rng->add_entropy_source(new High_Resolution_Timestamp); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + rng->add_entropy_source(new Intel_Rdrand); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + rng->add_entropy_source( + new Device_EntropySource( + split_on("/dev/random:/dev/srandom:/dev/urandom", ':') + ) + ); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) + rng->add_entropy_source( + new EGD_EntropySource(split_on("/var/run/egd-pool:/dev/egd-pool", ':')) + ); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) + rng->add_entropy_source(new Win32_CAPI_EntropySource); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_FTW) + rng->add_entropy_source(new FTW_EntropySource("/proc")); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + rng->add_entropy_source(new Win32_EntropySource); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) + rng->add_entropy_source(new BeOS_EntropySource); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX) + rng->add_entropy_source( + new Unix_EntropySource(split_on("/bin:/sbin:/usr/bin:/usr/sbin", ':')) + ); +#endif + } + +class Serialized_PRNG : public RandomNumberGenerator + { + public: + void randomize(byte out[], size_t len) + { + Mutex_Holder lock(mutex); + rng->randomize(out, len); + } + + bool is_seeded() const + { + Mutex_Holder lock(mutex); + return rng->is_seeded(); + } + + void clear() + { + Mutex_Holder lock(mutex); + rng->clear(); + } + + std::string name() const + { + Mutex_Holder lock(mutex); + return rng->name(); + } + + void reseed(size_t poll_bits) + { + Mutex_Holder lock(mutex); + rng->reseed(poll_bits); + } + + void add_entropy_source(EntropySource* es) + { + Mutex_Holder lock(mutex); + rng->add_entropy_source(es); + } + + void add_entropy(const byte in[], size_t len) + { + Mutex_Holder lock(mutex); + rng->add_entropy(in, len); + } + + // We do not own the mutex; Library_State does + Serialized_PRNG(RandomNumberGenerator* r, Mutex* m) : + mutex(m), rng(r) {} + + ~Serialized_PRNG() { delete rng; } + private: + Mutex* mutex; + RandomNumberGenerator* rng; + }; + +} + +RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af, + Mutex* mutex) + { + RandomNumberGenerator* rng = 0; + +#if defined(BOTAN_HAS_HMAC_RNG) + + rng = new HMAC_RNG(af.make_mac("HMAC(SHA-512)"), + af.make_mac("HMAC(SHA-256)")); + +#elif defined(BOTAN_HAS_RANDPOOL) + + rng = new Randpool(af.make_block_cipher("AES-256"), + af.make_mac("HMAC(SHA-256)")); + +#endif + + if(!rng) + throw Internal_Error("No usable RNG found enabled in build"); + + /* If X9.31 is available, use it to wrap the other RNG as a failsafe */ +#if defined(BOTAN_HAS_X931_RNG) + + rng = new ANSI_X931_RNG(af.make_block_cipher("AES-256"), rng); + +#endif + + add_entropy_sources(rng); + + rng->reseed(256); + + return new Serialized_PRNG(rng, mutex); + } + +} +/* +* Global State Management +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* @todo There should probably be a lock to avoid racy manipulation +* of the state among different threads +*/ + +namespace Global_State_Management { + +/* +* Botan's global state +*/ +namespace { + +Library_State* global_lib_state = 0; + +} + +/* +* Access the global state object +*/ +Library_State& global_state() + { + /* Lazy initialization. Botan still needs to be deinitialized later + on or memory might leak. + */ + if(!global_lib_state) + { + global_lib_state = new Library_State; + global_lib_state->initialize(true); + } + + return (*global_lib_state); + } + +/* +* Set a new global state object +*/ +void set_global_state(Library_State* new_state) + { + delete swap_global_state(new_state); + } + +/* +* Set a new global state object unless one already existed +*/ +bool set_global_state_unless_set(Library_State* new_state) + { + if(global_lib_state) + { + delete new_state; + return false; + } + else + { + delete swap_global_state(new_state); + return true; + } + } + +/* +* Swap two global state objects +*/ +Library_State* swap_global_state(Library_State* new_state) + { + Library_State* old_state = global_lib_state; + global_lib_state = new_state; + return old_state; + } + +/* +* Query if library is initialized +*/ +bool global_state_exists() + { + return (global_lib_state != 0); + } + +} + +} +/* +* Default Initialization Function +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Library Initialization +*/ +void LibraryInitializer::initialize(const std::string& arg_string) + { + bool thread_safe = false; + + const std::vector arg_list = split_on(arg_string, ' '); + for(size_t i = 0; i != arg_list.size(); ++i) + { + if(arg_list[i].size() == 0) + continue; + + std::string name, value; + + if(arg_list[i].find('=') == std::string::npos) + { + name = arg_list[i]; + value = "true"; + } + else + { + std::vector name_and_value = split_on(arg_list[i], '='); + name = name_and_value[0]; + value = name_and_value[1]; + } + + bool is_on = + (value == "1" || value == "true" || value == "yes" || value == "on"); + + if(name == "thread_safe") + thread_safe = is_on; + } + + try + { + /* + This two stage initialization process is because Library_State's + constructor will implicitly refer to global state through the + allocators and so forth, so global_state() has to be a valid + reference before initialize() can be called. Yeah, gross. + */ + Global_State_Management::set_global_state(new Library_State); + + global_state().initialize(thread_safe); + } + catch(...) + { + deinitialize(); + throw; + } + } + +/* +* Library Shutdown +*/ +void LibraryInitializer::deinitialize() + { + Global_State_Management::set_global_state(0); + } + +} +/* +* Library Internal/Global State +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_HAS_SELFTESTS) +#endif + +#if defined(BOTAN_HAS_MUTEX_PTHREAD) +#elif defined(BOTAN_HAS_MUTEX_WIN32) +#endif + +#if defined(BOTAN_HAS_ALLOC_MMAP) +#endif + +#if defined(BOTAN_HAS_ENGINE_ASSEMBLER) +#endif + +#if defined(BOTAN_HAS_ENGINE_AES_ISA) +#endif + +#if defined(BOTAN_HAS_ENGINE_SIMD) +#endif + +#if defined(BOTAN_HAS_ENGINE_GNU_MP) +#endif + +#if defined(BOTAN_HAS_ENGINE_OPENSSL) +#endif + +namespace Botan { + +/* +* Get a new mutex object +*/ +Mutex* Library_State::get_mutex() const + { + return mutex_factory->make(); + } + +/* +* Get an allocator by its name +*/ +Allocator* Library_State::get_allocator(const std::string& type) const + { + Mutex_Holder lock(allocator_lock); + + if(type != "") + return search_map(alloc_factory, type, 0); + + if(!cached_default_allocator) + { + cached_default_allocator = + search_map(alloc_factory, + default_allocator_name, 0); + } + + return cached_default_allocator; + } + +/* +* Create a new name to object mapping +*/ +void Library_State::add_allocator(Allocator* allocator) + { + Mutex_Holder lock(allocator_lock); + + allocator->init(); + + allocators.push_back(allocator); + alloc_factory[allocator->type()] = allocator; + } + +/* +* Set the default allocator type +*/ +void Library_State::set_default_allocator(const std::string& type) + { + Mutex_Holder lock(allocator_lock); + + if(type == "") + return; + + default_allocator_name = type; + cached_default_allocator = 0; + } + +/* +* Get a configuration value +*/ +std::string Library_State::get(const std::string& section, + const std::string& key) const + { + Mutex_Holder lock(config_lock); + + return search_map(config, + section + "/" + key, ""); + } + +/* +* See if a particular option has been set +*/ +bool Library_State::is_set(const std::string& section, + const std::string& key) const + { + Mutex_Holder lock(config_lock); + + return config.count(section + "/" + key) != 0; + } + +/* +* Set a configuration value +*/ +void Library_State::set(const std::string& section, const std::string& key, + const std::string& value, bool overwrite) + { + Mutex_Holder lock(config_lock); + + std::string full_key = section + "/" + key; + + std::map::const_iterator i = + config.find(full_key); + + if(overwrite || i == config.end() || i->second == "") + config[full_key] = value; + } + +/* +* Add an alias +*/ +void Library_State::add_alias(const std::string& key, const std::string& value) + { + set("alias", key, value); + } + +/* +* Dereference an alias to a fixed name +*/ +std::string Library_State::deref_alias(const std::string& key) const + { + std::string result = key; + while(is_set("alias", result)) + result = get("alias", result); + return result; + } + +/* +* Return a reference to the Algorithm_Factory +*/ +Algorithm_Factory& Library_State::algorithm_factory() const + { + if(!m_algorithm_factory) + throw Invalid_State("Uninitialized in Library_State::algorithm_factory"); + return *m_algorithm_factory; + } + +/* +* Return a reference to the global PRNG +*/ +RandomNumberGenerator& Library_State::global_rng() + { + Mutex_Holder lock(global_rng_lock); + + if(!global_rng_ptr) + global_rng_ptr = make_global_rng(algorithm_factory(), + global_rng_lock); + + return *global_rng_ptr; + } + +/* +* Load a set of modules +*/ +void Library_State::initialize(bool thread_safe) + { + CPUID::initialize(); + + if(mutex_factory) + throw Invalid_State("Library_State has already been initialized"); + + if(!thread_safe) + { + mutex_factory = new Noop_Mutex_Factory; + } + else + { +#if defined(BOTAN_HAS_MUTEX_PTHREAD) + mutex_factory = new Pthread_Mutex_Factory; +#elif defined(BOTAN_HAS_MUTEX_WIN32) + mutex_factory = new Win32_Mutex_Factory; +#else + throw Invalid_State("Could not find a thread-safe mutex object to use"); +#endif + } + + allocator_lock = get_mutex(); + config_lock = get_mutex(); + global_rng_lock = get_mutex(); + + default_allocator_name = has_mlock() ? "locking" : "malloc"; + + add_allocator(new Malloc_Allocator); + add_allocator(new Locking_Allocator(get_mutex())); + +#if defined(BOTAN_HAS_ALLOC_MMAP) + add_allocator(new MemoryMapping_Allocator(get_mutex())); +#endif + + load_default_config(); + + m_algorithm_factory = new Algorithm_Factory(*mutex_factory); + +#if defined(BOTAN_HAS_ENGINE_GNU_MP) + algorithm_factory().add_engine(new GMP_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_OPENSSL) + algorithm_factory().add_engine(new OpenSSL_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_AES_ISA) + algorithm_factory().add_engine(new AES_ISA_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_SIMD) + algorithm_factory().add_engine(new SIMD_Engine); +#endif + +#if defined(BOTAN_HAS_ENGINE_ASSEMBLER) + algorithm_factory().add_engine(new Assembler_Engine); +#endif + + algorithm_factory().add_engine(new Core_Engine); + +#if defined(BOTAN_HAS_SELFTESTS) + confirm_startup_self_tests(algorithm_factory()); +#endif + } + +/* +* Library_State Constructor +*/ +Library_State::Library_State() + { + mutex_factory = 0; + allocator_lock = config_lock = 0; + cached_default_allocator = 0; + m_algorithm_factory = 0; + + global_rng_lock = 0; + global_rng_ptr = 0; + } + +/* +* Library_State Destructor +*/ +Library_State::~Library_State() + { + delete m_algorithm_factory; + delete global_rng_ptr; + + cached_default_allocator = 0; + + for(size_t i = 0; i != allocators.size(); ++i) + { + allocators[i]->destroy(); + delete allocators[i]; + } + + delete global_rng_lock; + delete allocator_lock; + delete mutex_factory; + delete config_lock; + } + +} +/* +* Algorithm Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Query if an algorithm exists +*/ +bool have_algorithm(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(af.prototype_block_cipher(name)) + return true; + if(af.prototype_stream_cipher(name)) + return true; + if(af.prototype_hash_function(name)) + return true; + if(af.prototype_mac(name)) + return true; + return false; + } + +/* +* Query the block size of a cipher or hash +*/ +size_t block_size_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* cipher = af.prototype_block_cipher(name)) + return cipher->block_size(); + + if(const HashFunction* hash = af.prototype_hash_function(name)) + return hash->hash_block_size(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the output_length() of a hash or MAC +*/ +size_t output_length_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const HashFunction* hash = af.prototype_hash_function(name)) + return hash->output_length(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->output_length(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the minimum allowed key length of an algorithm implementation +*/ +size_t min_keylength_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().minimum_keylength(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().minimum_keylength(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().minimum_keylength(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the maximum allowed keylength of an algorithm implementation +*/ +size_t max_keylength_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().maximum_keylength(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().maximum_keylength(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().maximum_keylength(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the number of byte a valid key must be a multiple of +*/ +size_t keylength_multiple_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().keylength_multiple(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().keylength_multiple(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().keylength_multiple(); + + throw Algorithm_Not_Found(name); + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + Algorithm_Factory::Engine_Iterator i(af); + + while(Engine* engine = i.next()) + { + if(Keyed_Filter* algo = engine->get_cipher(algo_spec, direction, af)) + return algo; + } + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, direction); + cipher->set_key(key); + + if(iv.length()) + cipher->set_iv(iv); + + return cipher; + } + +/* +* Get a cipher object +*/ +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction) + { + return get_cipher(algo_spec, + key, InitializationVector(), direction); + } + +} +/* +* OID Registry +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace OIDS { + +/* +* Register an OID to string mapping +*/ +void add_oid(const OID& oid, const std::string& name) + { + const std::string oid_str = oid.as_string(); + + if(!global_state().is_set("oid2str", oid_str)) + global_state().set("oid2str", oid_str, name); + if(!global_state().is_set("str2oid", name)) + global_state().set("str2oid", name, oid_str); + } + +/* +* Do an OID to string lookup +*/ +std::string lookup(const OID& oid) + { + std::string name = global_state().get("oid2str", oid.as_string()); + if(name == "") + return oid.as_string(); + return name; + } + +/* +* Do a string to OID lookup +*/ +OID lookup(const std::string& name) + { + std::string value = global_state().get("str2oid", name); + if(value != "") + return OID(value); + + try + { + return OID(name); + } + catch(...) + { + throw Lookup_Error("No object identifier found for " + name); + } + } + +/* +* Check to see if an OID exists in the table +*/ +bool have_oid(const std::string& name) + { + return global_state().is_set("str2oid", name); + } + +/* +* Check to see if an OID exists in the table +*/ +bool name_of(const OID& oid, const std::string& name) + { + return (oid == lookup(name)); + } + +} + +} +/* +* Default Policy +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* OID loading helper function +*/ +void add_oid(Library_State& config, + const std::string& oid_str, + const std::string& name) + { + if(!config.is_set("oid2str", oid_str)) + config.set("oid2str", oid_str, name); + if(!config.is_set("str2oid", name)) + config.set("str2oid", name, oid_str); + } + +/* +* Load all of the default OIDs +*/ +void set_default_oids(Library_State& config) + { + /* Public key types */ + add_oid(config, "1.2.840.113549.1.1.1", "RSA"); + add_oid(config, "2.5.8.1.1", "RSA"); // RSA alternate + add_oid(config, "1.2.840.10040.4.1", "DSA"); + add_oid(config, "1.2.840.10046.2.1", "DH"); + add_oid(config, "1.3.6.1.4.1.3029.1.2.1", "ElGamal"); + add_oid(config, "1.3.6.1.4.1.25258.1.1", "RW"); + add_oid(config, "1.3.6.1.4.1.25258.1.2", "NR"); + + // X9.62 ecPublicKey, valid for ECDSA and ECDH (RFC 3279 sec 2.3.5) + add_oid(config, "1.2.840.10045.2.1", "ECDSA"); + + /* + * This is an OID defined for ECDH keys though rarely used for such. + * In this configuration it is accepted on decoding, but not used for + * encoding. You can enable it for encoding by calling + * global_state().set("str2oid", "ECDH", "1.3.132.1.12") + * from your application code. + */ + config.set("oid2str", "1.3.132.1.12", "ECDH"); + + add_oid(config, "1.2.643.2.2.19", "GOST-34.10"); // RFC 4491 + + /* Ciphers */ + add_oid(config, "1.3.14.3.2.7", "DES/CBC"); + add_oid(config, "1.2.840.113549.3.7", "TripleDES/CBC"); + add_oid(config, "1.2.840.113549.3.2", "RC2/CBC"); + add_oid(config, "1.2.840.113533.7.66.10", "CAST-128/CBC"); + add_oid(config, "2.16.840.1.101.3.4.1.2", "AES-128/CBC"); + add_oid(config, "2.16.840.1.101.3.4.1.22", "AES-192/CBC"); + add_oid(config, "2.16.840.1.101.3.4.1.42", "AES-256/CBC"); + add_oid(config, "1.2.410.200004.1.4", "SEED/CBC"); // RFC 4010 + add_oid(config, "1.3.6.1.4.1.25258.3.1", "Serpent/CBC"); + + /* Hash Functions */ + add_oid(config, "1.2.840.113549.2.5", "MD5"); + add_oid(config, "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)"); + + add_oid(config, "1.3.14.3.2.26", "SHA-160"); + add_oid(config, "2.16.840.1.101.3.4.2.4", "SHA-224"); + add_oid(config, "2.16.840.1.101.3.4.2.1", "SHA-256"); + add_oid(config, "2.16.840.1.101.3.4.2.2", "SHA-384"); + add_oid(config, "2.16.840.1.101.3.4.2.3", "SHA-512"); + + /* MACs */ + add_oid(config, "1.2.840.113549.2.7", "HMAC(SHA-1)"); + add_oid(config, "1.2.840.113549.2.8", "HMAC(SHA-224)"); + add_oid(config, "1.2.840.113549.2.9", "HMAC(SHA-256)"); + add_oid(config, "1.2.840.113549.2.10", "HMAC(SHA-384)"); + add_oid(config, "1.2.840.113549.2.11", "HMAC(SHA-512)"); + + /* Key Wrap */ + add_oid(config, "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES"); + add_oid(config, "1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2"); + add_oid(config, "1.2.840.113533.7.66.15", "KeyWrap.CAST-128"); + add_oid(config, "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128"); + add_oid(config, "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192"); + add_oid(config, "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256"); + + /* Compression */ + add_oid(config, "1.2.840.113549.1.9.16.3.8", "Compression.Zlib"); + + /* Public key signature schemes */ + add_oid(config, "1.2.840.113549.1.1.1", "RSA/EME-PKCS1-v1_5"); + add_oid(config, "1.2.840.113549.1.1.2", "RSA/EMSA3(MD2)"); + add_oid(config, "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)"); + add_oid(config, "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)"); + add_oid(config, "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)"); + add_oid(config, "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)"); + add_oid(config, "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)"); + add_oid(config, "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)"); + + add_oid(config, "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)"); + add_oid(config, "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)"); + add_oid(config, "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)"); + + add_oid(config, "0.4.0.127.0.7.1.1.4.1.1", "ECDSA/EMSA1_BSI(SHA-160)"); + add_oid(config, "0.4.0.127.0.7.1.1.4.1.2", "ECDSA/EMSA1_BSI(SHA-224)"); + add_oid(config, "0.4.0.127.0.7.1.1.4.1.3", "ECDSA/EMSA1_BSI(SHA-256)"); + add_oid(config, "0.4.0.127.0.7.1.1.4.1.4", "ECDSA/EMSA1_BSI(SHA-384)"); + add_oid(config, "0.4.0.127.0.7.1.1.4.1.5", "ECDSA/EMSA1_BSI(SHA-512)"); + add_oid(config, "0.4.0.127.0.7.1.1.4.1.6", "ECDSA/EMSA1_BSI(RIPEMD-160)"); + + add_oid(config, "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)"); + add_oid(config, "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)"); + add_oid(config, "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)"); + add_oid(config, "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)"); + add_oid(config, "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)"); + + add_oid(config, "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)"); + + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.1", "RW/EMSA2(RIPEMD-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.2", "RW/EMSA2(SHA-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.3", "RW/EMSA2(SHA-224)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.4", "RW/EMSA2(SHA-256)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.5", "RW/EMSA2(SHA-384)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.1.6", "RW/EMSA2(SHA-512)"); + + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.1", "RW/EMSA4(RIPEMD-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.2", "RW/EMSA4(SHA-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.3", "RW/EMSA4(SHA-224)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.4", "RW/EMSA4(SHA-256)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.5", "RW/EMSA4(SHA-384)"); + add_oid(config, "1.3.6.1.4.1.25258.2.1.2.6", "RW/EMSA4(SHA-512)"); + + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.1", "NR/EMSA2(RIPEMD-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.2", "NR/EMSA2(SHA-160)"); + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.3", "NR/EMSA2(SHA-224)"); + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.4", "NR/EMSA2(SHA-256)"); + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.5", "NR/EMSA2(SHA-384)"); + add_oid(config, "1.3.6.1.4.1.25258.2.2.1.6", "NR/EMSA2(SHA-512)"); + + add_oid(config, "2.5.4.3", "X520.CommonName"); + add_oid(config, "2.5.4.4", "X520.Surname"); + add_oid(config, "2.5.4.5", "X520.SerialNumber"); + add_oid(config, "2.5.4.6", "X520.Country"); + add_oid(config, "2.5.4.7", "X520.Locality"); + add_oid(config, "2.5.4.8", "X520.State"); + add_oid(config, "2.5.4.10", "X520.Organization"); + add_oid(config, "2.5.4.11", "X520.OrganizationalUnit"); + add_oid(config, "2.5.4.12", "X520.Title"); + add_oid(config, "2.5.4.42", "X520.GivenName"); + add_oid(config, "2.5.4.43", "X520.Initials"); + add_oid(config, "2.5.4.44", "X520.GenerationalQualifier"); + add_oid(config, "2.5.4.46", "X520.DNQualifier"); + add_oid(config, "2.5.4.65", "X520.Pseudonym"); + + add_oid(config, "1.2.840.113549.1.5.12", "PKCS5.PBKDF2"); + add_oid(config, "1.2.840.113549.1.5.1", "PBE-PKCS5v15(MD2,DES/CBC)"); + add_oid(config, "1.2.840.113549.1.5.4", "PBE-PKCS5v15(MD2,RC2/CBC)"); + add_oid(config, "1.2.840.113549.1.5.3", "PBE-PKCS5v15(MD5,DES/CBC)"); + add_oid(config, "1.2.840.113549.1.5.6", "PBE-PKCS5v15(MD5,RC2/CBC)"); + add_oid(config, "1.2.840.113549.1.5.10", "PBE-PKCS5v15(SHA-160,DES/CBC)"); + add_oid(config, "1.2.840.113549.1.5.11", "PBE-PKCS5v15(SHA-160,RC2/CBC)"); + add_oid(config, "1.2.840.113549.1.5.13", "PBE-PKCS5v20"); + + add_oid(config, "1.2.840.113549.1.9.1", "PKCS9.EmailAddress"); + add_oid(config, "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName"); + add_oid(config, "1.2.840.113549.1.9.3", "PKCS9.ContentType"); + add_oid(config, "1.2.840.113549.1.9.4", "PKCS9.MessageDigest"); + add_oid(config, "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword"); + add_oid(config, "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest"); + + add_oid(config, "1.2.840.113549.1.7.1", "CMS.DataContent"); + add_oid(config, "1.2.840.113549.1.7.2", "CMS.SignedData"); + add_oid(config, "1.2.840.113549.1.7.3", "CMS.EnvelopedData"); + add_oid(config, "1.2.840.113549.1.7.5", "CMS.DigestedData"); + add_oid(config, "1.2.840.113549.1.7.6", "CMS.EncryptedData"); + add_oid(config, "1.2.840.113549.1.9.16.1.2", "CMS.AuthenticatedData"); + add_oid(config, "1.2.840.113549.1.9.16.1.9", "CMS.CompressedData"); + + add_oid(config, "2.5.29.14", "X509v3.SubjectKeyIdentifier"); + add_oid(config, "2.5.29.15", "X509v3.KeyUsage"); + add_oid(config, "2.5.29.17", "X509v3.SubjectAlternativeName"); + add_oid(config, "2.5.29.18", "X509v3.IssuerAlternativeName"); + add_oid(config, "2.5.29.19", "X509v3.BasicConstraints"); + add_oid(config, "2.5.29.20", "X509v3.CRLNumber"); + add_oid(config, "2.5.29.21", "X509v3.ReasonCode"); + add_oid(config, "2.5.29.23", "X509v3.HoldInstructionCode"); + add_oid(config, "2.5.29.24", "X509v3.InvalidityDate"); + add_oid(config, "2.5.29.32", "X509v3.CertificatePolicies"); + add_oid(config, "2.5.29.35", "X509v3.AuthorityKeyIdentifier"); + add_oid(config, "2.5.29.36", "X509v3.PolicyConstraints"); + add_oid(config, "2.5.29.37", "X509v3.ExtendedKeyUsage"); + + add_oid(config, "2.5.29.32.0", "X509v3.AnyPolicy"); + + add_oid(config, "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth"); + add_oid(config, "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth"); + add_oid(config, "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning"); + add_oid(config, "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection"); + add_oid(config, "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem"); + add_oid(config, "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel"); + add_oid(config, "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser"); + add_oid(config, "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping"); + add_oid(config, "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning"); + + add_oid(config, "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr"); + + /* ECC domain parameters */ + + add_oid(config, "1.3.132.0.6", "secp112r1"); + add_oid(config, "1.3.132.0.7", "secp112r2"); + add_oid(config, "1.3.132.0.8", "secp160r1"); + add_oid(config, "1.3.132.0.9", "secp160k1"); + add_oid(config, "1.3.132.0.10", "secp256k1"); + add_oid(config, "1.3.132.0.28", "secp128r1"); + add_oid(config, "1.3.132.0.29", "secp128r2"); + add_oid(config, "1.3.132.0.30", "secp160r2"); + add_oid(config, "1.3.132.0.31", "secp192k1"); + add_oid(config, "1.3.132.0.32", "secp224k1"); + add_oid(config, "1.3.132.0.33", "secp224r1"); + add_oid(config, "1.3.132.0.34", "secp384r1"); + add_oid(config, "1.3.132.0.35", "secp521r1"); + + add_oid(config, "1.2.840.10045.3.1.1", "secp192r1"); + add_oid(config, "1.2.840.10045.3.1.2", "x962_p192v2"); + add_oid(config, "1.2.840.10045.3.1.3", "x962_p192v3"); + add_oid(config, "1.2.840.10045.3.1.4", "x962_p239v1"); + add_oid(config, "1.2.840.10045.3.1.5", "x962_p239v2"); + add_oid(config, "1.2.840.10045.3.1.6", "x962_p239v3"); + add_oid(config, "1.2.840.10045.3.1.7", "secp256r1"); + + add_oid(config, "1.3.36.3.3.2.8.1.1.1", "brainpool160r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.3", "brainpool192r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.5", "brainpool224r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.7", "brainpool256r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.9", "brainpool320r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.11", "brainpool384r1"); + add_oid(config, "1.3.36.3.3.2.8.1.1.13", "brainpool512r1"); + + add_oid(config, "1.2.643.2.2.35.1", "gost_256A"); + add_oid(config, "1.2.643.2.2.36.0", "gost_256A"); + + /* CVC */ + add_oid(config, "0.4.0.127.0.7.3.1.2.1", + "CertificateHolderAuthorizationTemplate"); + } + +/* +* Set the default algorithm aliases +*/ +void set_default_aliases(Library_State& config) + { + config.add_alias("OpenPGP.Cipher.1", "IDEA"); + config.add_alias("OpenPGP.Cipher.2", "TripleDES"); + config.add_alias("OpenPGP.Cipher.3", "CAST-128"); + config.add_alias("OpenPGP.Cipher.4", "Blowfish"); + config.add_alias("OpenPGP.Cipher.5", "SAFER-SK(13)"); + config.add_alias("OpenPGP.Cipher.7", "AES-128"); + config.add_alias("OpenPGP.Cipher.8", "AES-192"); + config.add_alias("OpenPGP.Cipher.9", "AES-256"); + config.add_alias("OpenPGP.Cipher.10", "Twofish"); + + config.add_alias("OpenPGP.Digest.1", "MD5"); + config.add_alias("OpenPGP.Digest.2", "SHA-1"); + config.add_alias("OpenPGP.Digest.3", "RIPEMD-160"); + config.add_alias("OpenPGP.Digest.5", "MD2"); + config.add_alias("OpenPGP.Digest.6", "Tiger(24,3)"); + config.add_alias("OpenPGP.Digest.8", "SHA-256"); + + config.add_alias("TLS.Digest.0", "Parallel(MD5,SHA-160)"); + + config.add_alias("EME-PKCS1-v1_5", "PKCS1v15"); + config.add_alias("OAEP-MGF1", "EME1"); + config.add_alias("EME-OAEP", "EME1"); + config.add_alias("X9.31", "EMSA2"); + config.add_alias("EMSA-PKCS1-v1_5", "EMSA3"); + config.add_alias("PSS-MGF1", "EMSA4"); + config.add_alias("EMSA-PSS", "EMSA4"); + + config.add_alias("3DES", "TripleDES"); + config.add_alias("DES-EDE", "TripleDES"); + config.add_alias("CAST5", "CAST-128"); + config.add_alias("SHA1", "SHA-160"); + config.add_alias("SHA-1", "SHA-160"); + config.add_alias("MARK-4", "ARC4(256)"); + config.add_alias("OMAC", "CMAC"); + config.add_alias("GOST", "GOST-28147-89"); + } + +/* +* Set the built-in discrete log groups +*/ +void set_default_dl_groups(Library_State& config) + { + config.set("dl", "modp/ietf/768", + "-----BEGIN X942 DH PARAMETERS-----" + "MIHIAmEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFK" + "CHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjo2IP//" + "////////AgECAmB//////////+SH7VEQtGEaYmMxRcBuDmiUgScERTPmOgEF31Md" + "ic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Catrao4SLyQtq7MS8/Y3omIXTT" + "HRsQf/////////8=" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/1024", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBCgKBgQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si" + "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r" + "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezmU4H//////////wIBAgKBgH//" + "////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXfUx2JzZEopQQ8xxoCbvfK" + "jNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYhdNMb9rWF/65begNb9vcc" + "Nf2tRM/S10+SCL4lj/MklDMo9nMpwP//////////" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/1024", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBCgKBgQDurwq5rbON1pwz+Ar6j8XoYHJhh3X/PAueojFMnCVldtZ033SW6oHT" + "ODtIE9aSxuDg1djiULmL5I5JXB1gidrRXcfXtGFU1rbOjvStabFdSYJVmyl7zxiF" + "xSn1ZmYOV+xo7bw8BXJswC/Uy/SXbqqa/VE4/oN2Q1ufxh0vwOsG4wIBAgKBgHdX" + "hVzW2cbrThn8BX1H4vQwOTDDuv+eBc9RGKZOErK7azpvukt1QOmcHaQJ60ljcHBq" + "7HEoXMXyRySuDrBE7Wiu4+vaMKprW2dHela02K6kwSrNlL3njELilPqzMwcr9jR2" + "3h4CuTZgF+pl+ku3VU1+qJx/Qbshrc/jDpfgdYNx" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/1536", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIBigKBwQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5si" + "UUoIeY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummN+1r" + "C/9ctvQGt+3uOGv7Womfpa6fJBF8Sx/mSShmUezkWz3CAHy4oWO/BZjaSDYcVdOa" + "aRY/qP0kz1+DZV0j3KOtlhxi81YghVK7ntUpB3CWlm1nDDVOSryYBPF0bAjKI3Mn" + "//////////8CAQICgcB//////////+SH7VEQtGEaYmMxRcBuDmiUgScERTPmOgEF" + "31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Catrao4SLyQtq7MS8/Y3om" + "IXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQzKPZyLZ7hAD5cULHfgsxt" + "JBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qUg7hLSzazhhqnJV5MAni6" + "NgRlEbmT//////////8=" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/1536", + "-----BEGIN DH PARAMETERS-----" + "MIHHAoHBAJ3vPK+5OSd6sfEqhheke7vbpR30maxMgL7uqWFLGcxNX09fVW4ny95R" + "xqlL5GB6KRVYkDug0PhDgLZVu5oi6NzfAop87Gfw0IE0sci5eYkUm2CeC+O6tj1H" + "VIOB28Wx/HZOP0tT3Z2hFYv9PiucjPVu3wGVOTSWJ9sv1T0kt8SGZXcuQ31sf4zk" + "QnNK98y3roN8Jkrjqb64f4ov6bi1KS5aAh//XpFHnoznoowkQsbzFRgPk0maI03P" + "duP+0TX5uwIBAg==" + "-----END DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/2048", + "-----BEGIN X942 DH PARAMETERS-----" + "MIICDAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAgKCAQB//////////+SH7VEQtGEa" + "YmMxRcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4ob" + "p/Catrao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/z" + "JJQzKPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqld" + "z2qUg7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH" + "2uKu+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVZVNH//////////" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/2048", + "-----BEGIN X942 DH PARAMETERS-----" + "MIICDAKCAQEArGvbQTJKmpvxZt5eE4lYL69ytmUZh+4H/DGSlD21YFCjcynLtKCZ" + "7YGT4HV3Z6E91SMSq0sDMQ3Nf0ip2gT9UOgIOWntt2ewz2CVF5oWOrNmGgX71fqq" + "6CkYqZYvC5O4Vfl5k+yXXuqoDXQK2/T/dHNZ0EHVwz6nHSgeRGsUdzvKl7Q6I/uA" + "Fna9IHpDbGSB8dK5B4cXRhpbnTLmiPh3SFRFI7UksNV9Xqd6J3XS7PoDLPvb9S+z" + "eGFgJ5AE5Xrmr4dOcwPOUymczAQce8MI2CpWmPOo0MOCca41+Onb+7aUtcgD2J96" + "5DXeI21SX1R1m2XjcvzWjvIPpxEfnkr/cwIBAgKCAQBWNe2gmSVNTfizby8JxKwX" + "17lbMozD9wP+GMlKHtqwKFG5lOXaUEz2wMnwOruz0J7qkYlVpYGYhua/pFTtAn6o" + "dAQctPbbs9hnsEqLzQsdWbMNAv3q/VV0FIxUyxeFydwq/LzJ9kuvdVQGugVt+n+6" + "OazoIOrhn1OOlA8iNYo7neVL2h0R/cALO16QPSG2MkD46VyDw4ujDS3OmXNEfDuk" + "KiKR2pJYar6vU70Tuul2fQGWfe36l9m8MLATyAJyvXNXw6c5gecplM5mAg494YRs" + "FStMedRoYcE41xr8dO3920pa5AHsT71yGu8RtqkvqjrNsvG5fmtHeQfTiI/PJX+5" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/3072", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIDDAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS" + "yv//////////AgECAoIBgH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6" + "AQXfUx2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9j" + "eiYhdNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+C" + "zG0kGw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwC" + "eLo2BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuM" + "HMqkvnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeF" + "RXU4q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQy" + "bDsBOZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohH" + "JcFokFSdaWV//////////w==" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/3072", + "-----BEGIN DH PARAMETERS-----" + "MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS" + "yv//////////AgEF" + "-----END DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/4096", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIEDAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQICggIA" + "f//////////kh+1RELRhGmJjMUXAbg5olIEnBEUz5joBBd9THYnNkSilBDzHGgJu" + "98qM2eadIY2YFYU2+S+KG6fwmra2qOEi8kLauzEvP2N6JiF00xv2tYX/rlt6A1v2" + "9xw1/a1Ez9LXT5IIviWP8ySUMyj2ci2e4QA+XFCx34LMbSQbDirpzTSLH9R+kmev" + "wbKuke5R1ssOMXmrEEKpXc9qlIO4S0s2s4YapyVeTAJ4ujYEZQwQvhlILyMXG2cd" + "8c87lgwHQwHNk8HRdgPRR9rirvg3pilk7xXl+0qsC4wcyqS+dUq1corpEwxMfQKI" + "CrlHLUVVYhbWmYuGgig9GdQqkNXvjl0ydn3Cgixt94VFdTirroMGPtnLh8LTcPJj" + "1frXRm2EmeuPRkpwJRKwzudx6RMNaXc1+Jf9A2zFBDJsOwE5n2Q1MikPlYwLvZAG" + "XfCLq70wrrY7hMRgXWyjcQRxJ9A6ctWYoe2t/nB+iEclwWiQVJCEAI05HglTw/Nr" + "xDjNCF7dLZNM4ZOMNXpxHg1KNBpbCoXtEsH05RVqJnRt3eFtgm9HfJdHfgoP32VT" + "FD4so6c14C7M2Usn0Ehh0RGd0MMorfP2j7CUuGdxa9fcDe67ELgkDmgDSJPq2C1U" + "ydp1TEbH7uDDf9vuSFNgR6b6GuSaAxjM//////////8=" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/4096", + "-----BEGIN DH PARAMETERS-----" + "MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQU=" + "-----END DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/6144", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIGDAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA" + "JP//////////AoIDAH//////////5IftURC0YRpiYzFFwG4OaJSBJwRFM+Y6AQXf" + "Ux2JzZEopQQ8xxoCbvfKjNnmnSGNmBWFNvkvihun8Jq2tqjhIvJC2rsxLz9jeiYh" + "dNMb9rWF/65begNb9vccNf2tRM/S10+SCL4lj/MklDMo9nItnuEAPlxQsd+CzG0k" + "Gw4q6c00ix/UfpJnr8GyrpHuUdbLDjF5qxBCqV3PapSDuEtLNrOGGqclXkwCeLo2" + "BGUMEL4ZSC8jFxtnHfHPO5YMB0MBzZPB0XYD0Ufa4q74N6YpZO8V5ftKrAuMHMqk" + "vnVKtXKK6RMMTH0CiAq5Ry1FVWIW1pmLhoIoPRnUKpDV745dMnZ9woIsbfeFRXU4" + "q66DBj7Zy4fC03DyY9X610ZthJnrj0ZKcCUSsM7ncekTDWl3NfiX/QNsxQQybDsB" + "OZ9kNTIpD5WMC72QBl3wi6u9MK62O4TEYF1so3EEcSfQOnLVmKHtrf5wfohHJcFo" + "kFSQhACNOR4JU8Pza8Q4zQhe3S2TTOGTjDV6cR4NSjQaWwqF7RLB9OUVaiZ0bd3h" + "bYJvR3yXR34KD99lUxQ+LKOnNeAuzNlLJ9BIYdERndDDKK3z9o+wlLhncWvX3A3u" + "uxC4JA5oA0iT6tgtVMnadUxGx+7gw3/b7khTYEem+hrkmgFCSRth/VppPjgTYOpu" + "WTATI29kuo87Ht0b3vx/ygNWzymHcu2cF6CYANdYNSn2yBPsGIvLk9hDLUSMbR9t" + "9efNinaiZzZdZ2pdje2/iiPzZhKlmZAoqJXr16E33HoAm8ZpX6zB5QDjJcl2eBl1" + "Cui5DoH6QWvnNzp/e2qvOBejTAZBWtQgGMgFjk8s8+S/32P0eZHUvT8bZkRfB46i" + "2/+sLWKl6gPZFaCqVWZHtr9fpHDsCmYvaQfAG/BTy4r3eU3xlANQ6sXb4u07eqhV" + "HsUP3/h1jOZY0Ynqrm0rZPYXeUsZHD/0a7ceAjQCH0ezH6Qwdwlflq2Fujprc0p8" + "jzbmIBJ//////////wIBAg==" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/6144", + "-----BEGIN DH PARAMETERS-----" + "MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA" + "JP//////////AgEF" + "-----END DH PARAMETERS-----"); + + config.set("dl", "modp/ietf/8192", + "-----BEGIN X942 DH PARAMETERS-----" + "MIIIDAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R" + "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk" + "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw" + "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4" + "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i" + "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU" + "38gfVuiAuW5xYMmA3Zjt09///////////wKCBAB//////////+SH7VEQtGEaYmMx" + "RcBuDmiUgScERTPmOgEF31Mdic2RKKUEPMcaAm73yozZ5p0hjZgVhTb5L4obp/Ca" + "trao4SLyQtq7MS8/Y3omIXTTG/a1hf+uW3oDW/b3HDX9rUTP0tdPkgi+JY/zJJQz" + "KPZyLZ7hAD5cULHfgsxtJBsOKunNNIsf1H6SZ6/Bsq6R7lHWyw4xeasQQqldz2qU" + "g7hLSzazhhqnJV5MAni6NgRlDBC+GUgvIxcbZx3xzzuWDAdDAc2TwdF2A9FH2uKu" + "+DemKWTvFeX7SqwLjBzKpL51SrVyiukTDEx9AogKuUctRVViFtaZi4aCKD0Z1CqQ" + "1e+OXTJ2fcKCLG33hUV1OKuugwY+2cuHwtNw8mPV+tdGbYSZ649GSnAlErDO53Hp" + "Ew1pdzX4l/0DbMUEMmw7ATmfZDUyKQ+VjAu9kAZd8IurvTCutjuExGBdbKNxBHEn" + "0Dpy1Zih7a3+cH6IRyXBaJBUkIQAjTkeCVPD82vEOM0IXt0tk0zhk4w1enEeDUo0" + "GlsKhe0SwfTlFWomdG3d4W2Cb0d8l0d+Cg/fZVMUPiyjpzXgLszZSyfQSGHREZ3Q" + "wyit8/aPsJS4Z3Fr19wN7rsQuCQOaANIk+rYLVTJ2nVMRsfu4MN/2+5IU2BHpvoa" + "5JoBQkkbYf1aaT44E2DqblkwEyNvZLqPOx7dG978f8oDVs8ph3LtnBegmADXWDUp" + "9sgT7BiLy5PYQy1EjG0fbfXnzYp2omc2XWdqXY3tv4oj82YSpZmQKKiV69ehN9x6" + "AJvGaV+sweUA4yXJdngZdQrouQ6B+kFr5zc6f3tqrzgXo0wGQVrUIBjIBY5PLPPk" + "v99j9HmR1L0/G2ZEXweOotv/rC1ipeoD2RWgqlVmR7a/X6Rw7ApmL2kHwBvwU8uK" + "93lN8ZQDUOrF2+LtO3qoVR7FD9/4dYzmWNGJ6q5tK2T2F3lLGRw/9Gu3HgI0Ah9H" + "sx+kMHcJX5athbo6a3NKfI823wisulHJN4l/cvIcO75bVJlvxmxfYmg53JjdHeQZ" + "W0bO6YA6D9PfxX4j9pK7e0m10hIzHVWxzi1yerQaEdo6FfjkvBHHi2XxzrKW8f7c" + "X35CRWyRERcCUgG+A4n1q9QNEfhjmjn+MjZ1GDWl5eRDF8HC7v1Opb/RYEP0PLQZ" + "gfat7p0DFZ562dE8UzaVCfwfonwW75iHcDpVtRsiy/RM0BKu4LJ5jmKEI0KO/NWk" + "DK72v1DY6ohev3Omuf15teGPZ9E0GsgjenXDz8kgBKHFpA42a8RNABdq9xwV5IyG" + "034BNyPKrHIjqzv01U8YKHE7K0pv5A+rdEBctziwZMBuzHbp7///////////AgEC" + "-----END X942 DH PARAMETERS-----"); + + config.set("dl", "modp/srp/8192", + "-----BEGIN DH PARAMETERS-----" + "MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R" + "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk" + "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw" + "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4" + "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i" + "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU" + "38gfVuiAuW5xYMmA3Zjt09///////////wIBEw==" + "-----END DH PARAMETERS-----"); + + config.set("dl", "dsa/jce/512", + "-----BEGIN DSA PARAMETERS-----" + "MIGdAkEA/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQT" + "xeEu0ImbzRMqzVDZkVG9xD7nN1kuFwIVAJYu3cw2nLqOuyYO5rahJtk0bjjFAkEA" + "3gtU76vylwh+5iPVylWIxkgo70/eT/uuHs0gBndrBbEbgeo83pvDlkwWh8UyW/Q9" + "fM76DQqGvl3/3dDRFD3NdQ==" + "-----END DSA PARAMETERS-----"); + + config.set("dl", "dsa/jce/768", + "-----BEGIN DSA PARAMETERS-----" + "MIHdAmEA6eZCWZ01XzfJf/01ZxILjiXJzUPpJ7OpZw++xdiQFBki0sOzrSSACTeZ" + "hp0ehGqrSfqwrSbSzmoiIZ1HC859d31KIfvpwnC1f2BwAvPO+Dk2lM9F7jaIwRqM" + "VqsSej2vAhUAnNvYTJ8awvOND4D0KrlS5zOL9RECYQDe7p717RUWzn5pXmcrjO5F" + "5s17NuDmOF+JS6hhY/bz5sbU6KgRRtQBfe/dccvZD6Akdlm4i3zByJT0gmn9Txqs" + "CjBTjf9rP8ds+xMcnnlltYhYqwpDtVczWRKoqlR/lWg=" + "-----END DSA PARAMETERS-----"); + + config.set("dl", "dsa/jce/1024", + "-----BEGIN DSA PARAMETERS-----" + "MIIBHgKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9" + "jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX" + "58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8V" + "IwvMspK5gqLrhAvwWBz1AoGARpYDUS4wJ4zTlHWV2yLuyYJqYyKtyXNE9B10DDJX" + "JMj577qn1NgD/4xgnc0QDrxb38+tfGpCX66nhuogUOvpg1HqH9of3yTWlHqmuaoj" + "dmlTgC9NfUqOy6BtGXaKJJH/sW0O+cQ6mbX3FnL/bwoktETQc20E04oaEyLa9s3Y" + "jJ0=" + "-----END DSA PARAMETERS-----"); + + config.set("dl", "dsa/botan/2048", + "-----BEGIN DSA PARAMETERS-----" + "MIICLAKCAQEAkcSKT9+898Aq6V59oSYSK13Shk9Vm4fo50oobVL1m9HeaN/WRdDg" + "DGDAgAMYkZgDdO61lKUyv9Z7mgnqxLhmOgeRDmjzlGX7cEDSXfE5MuusQ0elMOy6" + "YchU+biA08DDZgCAWHxFVm2t4mvVo5S+CTtMDyS1r/747GxbPlf7iQJam8FnaZMh" + "MeFtPJTvyrGNDfBhIDzFPmEDvHLVWUv9QMplOA9EqahR3LB1SV/AM6ilgHGhvXj+" + "BS9mVVZI60txnSr+i0iA+NrW8VgYuhePiSdMhwvpuW6wjEbEAEDMLv4d+xsYaN0x" + "nePDSjKmOrbrEiQgmkGWgMx5AtFyjU354QIhAIzX1FD4bwrZTu5M5GmodW0evRBY" + "JBlD6v+ws1RYXpJNAoIBAA2fXgdhtNvRgz1qsalhoJlsXyIwP3LYTBQPZ8Qx2Uq1" + "cVvqgaDJjTnOS8941rnryJXTT+idlAkdWEhhXvFfXobxHZb2yWniA936WDVkIKSc" + "tES1lbkBqTPP4HZ7WU8YoHt/kd7NukRriJkPePL/kfL+fNQ/0uRtGOraH3u2YCxh" + "f27zpLKE8v2boQo2BC3o+oeiyjZZf+yBFXoUheRAQd8CgwERy4gLvm7UlIFIhvll" + "zcMTX1zPE4Nyi/ZbgG+WksCxDWxMCcdabKO0ATyxarLBBfa+I66pAA6rIXiYX5cs" + "mAV+HIbkTnIYaI6krg82NtzKdFydzU5q/7Z8y8E9YTE=" + "-----END DSA PARAMETERS-----"); + + config.set("dl", "dsa/botan/3072", + "-----BEGIN DSA PARAMETERS-----" + "MIIDLAKCAYEA5LUIgHWWY1heFCRgyi2d/xMviuTIQN2jomZoiRJP5WOLhOiim3rz" + "+hIJvmv8S1By7Tsrc4e68/hX9HioAijvNgC3az3Pth0g00RlslBtLK+H3259wM6R" + "vS0Wekb2rcwxxTHk+cervbkq3fNbCoBsZikqX14X6WTdCZkDczrEKKs12A6m9oW/" + "uovkBo5UGK5eytno/wc94rY+Tn6tNciptwtb1Hz7iNNztm83kxk5sKtxvVWVgJCG" + "2gFVM30YWg5Ps2pRmxtiArhZHmACRJzxzTpmOE9tIHOxzXO+ypO68eGmEX0COPIi" + "rh7X/tGFqJDn9n+rj+uXU8wTSlGD3+h64llfe1wtn7tCJJ/dWVE+HTOWs+sv2GaE" + "8oWoRI/nV6ApiBxAdguU75Gb35dAw4OJWZ7FGm6btRmo4GhJHpzgovz+PLYNZs8N" + "+tIKjsaEBIaEphREV1vRck1zUrRKdgB3s71r04XOWwpyUMwL92jagpI4Buuc+7E4" + "hDcxthggjHWbAiEAs+vTZOxp74zzuvZDt1c0sWM5suSeXN4bWcHp+0DuDFsCggGA" + "K+0h7vg5ZKIwrom7px2ffDnFL8gim047x+WUTTKdoQ8BDqyee69sAJ/E6ylgcj4r" + "Vt9GY+TDrIAOkljeL3ZJ0gZ4KJP4Ze/KSY0u7zAHTqXop6smJxKk2UovOwuaku5A" + "D7OKPMWaXcfkNtXABLIuNQKDgbUck0B+sy1K4P1Cy0XhLQ7O6KJiOO3iCCp7FSIR" + "PGbO+NdFxs88uUX4TS9N4W1Epx3hmCcOE/A1U8iLjTI60LlIob8hA6lJl5tu0W+1" + "88lT2Vt8jojKZ9z1pjb7nKOdkkIV96iE7Wx+48ltjZcVQnl0t8Q1EoLhPTdz99KL" + "RS8QiSoTx1hzKN6kgntrNpsqjcFyrcWD9R8qZZjFSD5bxGewL5HQWcQC0Y4sJoD3" + "dqoG9JKAoscsF8xC1bbnQMXEsas8UcLtCSviotiwU65Xc9FCXtKwjwbi3VBZLfGk" + "eMFVkc39EVZP+I/zi3IdQjkv2kcyEtz9jS2IqXagCv/m//tDCjWeZMorNRyiQSOU" + "-----END DSA PARAMETERS-----"); + + config.set("ec", "secp112r1", + "-----BEGIN EC PARAMETERS-----" + "MHQCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDtt8Kr9i415mgHa+" + "rSCIBA5lnvi6BDkW7t6JEXArIgQdBAlIcjmZWl7na1X5wvCYqJzlr4ckwKI+Dg/3" + "dQACDwDbfCq/YuNedijfrGVhxQIBAQ==" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp112r2", + "-----BEGIN EC PARAMETERS-----" + "MHMCAQEwGgYHKoZIzj0BAQIPANt8Kr9i415mgHa+rSCLMCAEDmEnwkwF84oKqvZc" + "DvAsBA5R3vGBXbXtdPzDTIXXCQQdBEujCrXokrThZJ3QkoZDrc1G9YguN0fe826V" + "bpcCDjbfCq/YuNdZfKEFINBLAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp128r1", + "-----BEGIN EC PARAMETERS-----" + "MIGAAgEBMBwGByqGSM49AQECEQD////9////////////////MCQEEP////3/////" + "//////////wEEOh1ecEQefQ92CSZPCzuXtMEIQQWH/dSi4mbLQwoYHylLFuGz1rI" + "OVuv6xPALaKS3e16gwIRAP////4AAAAAdaMNG5A4oRUCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp128r2", + "-----BEGIN EC PARAMETERS-----" + "MH8CAQEwHAYHKoZIzj0BAQIRAP////3///////////////8wJAQQ1gMZmNGzu/6/" + "Wcybv/mu4QQQXu78o4DQKRncLGVYu22KXQQhBHtqpdheVymD5vsyp83rwUAntpFq" + "iU067nEG/oBfw0tEAhA/////f////74AJHIGE7WjAgEE" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp160k1", + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBQAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAQUAAAAAAAAAAAAAAAAAAAAAAAAAAcEKQQ7TDgs43qh" + "kqQBnnYwNvT13U1+u5OM+TUxj9zta8KChlMXM8PwPE/uAhUBAAAAAAAAAAAAAbj6" + "Ft+rmsoWtrMCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp160r1", + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD/////////////////////f////zAsBBT/////" + "////////////////f////AQUHJe+/FS9eotlrPifgdTUrcVl+kUEKQRKlrVojvVz" + "KEZkaYlow4u5E8v8giOmKFUxaJR9WdzJEgQjUTd6xfsyAhUBAAAAAAAAAAAAAfTI" + "+Seu08p1IlcCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp160r2", + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQD////////////////////+//+sczAsBBT/////" + "///////////////+//+scAQUtOE00/tZ64urVydJBGZNWvUDiLoEKQRS3LA0KToR" + "fh9P8Rsw9xmdMUTObf6v/vLjMfKW4HH6DfmYLP6n1D8uAhUBAAAAAAAAAAAAADUe" + "54aoGPOhoWsCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp192k1", + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD//////////////////////////v//7jcwNAQY" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAMEMQTbT/EOwFfpriawfQKAt/Q0HaXRsergbH2bLy9tnFYop4RBY9AVvoY0QIKq" + "iNleL50CGQD///////////////4m8vwXD2lGanTe/Y0CAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp192r1", + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBhkIQUZ5ZyA5w+n6atyJDBJ/rje7MFG" + "ubEEMQQYjagOsDCQ9ny/IOtDoYgA9P8K/YL/EBIHGSuV/8jaeGMQEe1rJM3Vc/l3" + "oR55SBECGQD///////////////+Z3vg2FGvJsbTSKDECAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp224k1", + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQD///////////////////////////////7//+Vt" + "MDwEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAUEOQShRVszTfCZ3zD8KKFppGfp5HB1qQ9+ZQ62t6Rcfgif" + "7X+6NEKCyvvW9+MZ98CwvVniykvbVW1hpQIdAQAAAAAAAAAAAAAAAAAB3OjS7GGE" + "yvCpcXafsfcCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp224r1", + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQD/////////////////////AAAAAAAAAAAAAAAB" + "MDwEHP////////////////////7///////////////4EHLQFCoUMBLOr9UEyVlBE" + "sLfXv9i6Jws5QyNV/7QEOQS3Dgy9a7S/fzITkLlKA8HTVsIRIjQygNYRXB0hvTdj" + "iLX3I/tMIt/mzUN1oFoHR2RE1YGZhQB+NAIdAP//////////////////FqLguPA+" + "E90pRVxcKj0CAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp256k1", + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD////////////////////////////////////+" + "///8LzBEBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQgAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEQQR5vmZ++dy7rFWgYpXOhwsHApv8" + "2y3OKNlZ8oFbFvgXmEg62ncmo8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA" + "/////////////////////rqu3OavSKA7v9JejNA2QUECAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp256r1", + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" + "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" + "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDydwN9" + "gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA" + "/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp384r1", + "-----BEGIN EC PARAMETERS-----" + "MIIBQAIBATA8BgcqhkjOPQEBAjEA////////////////////////////////////" + "//////7/////AAAAAAAAAAD/////MGQEMP//////////////////////////////" + "///////////+/////wAAAAAAAAAA/////AQwszEvp+I+5+SYjgVr4/gtGRgdnG7+" + "gUESAxQIj1ATh1rGVjmNii7RnSqFyO3T7CrvBGEEqofKIr6LBTeOscce8yCtdG4d" + "O2KLp5uYWfdB4IJUKjhVAvJdv1UpbDpUXjhydgq3NhfeSpYmLG9dnpi/kpLcKfj0" + "Hb0omhR86doxE7XwuMAKYLHOHX6BnXpDHXyQ6g5fAjEA////////////////////" + "////////////x2NNgfQ3Ld9YGg2ySLCneuzsGWrMxSlzAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "secp521r1", + "-----BEGIN EC PARAMETERS-----" + "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////" + "//////////////////////////////////////////////////8wgYgEQgH/////" + "////////////////////////////////////////////////////////////////" + "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ" + "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e" + "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5" + "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm" + "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////" + "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "1.3.6.1.4.1.8301.3.1.2.9.0.38", + "-----BEGIN EC PARAMETERS-----" + "MIIBrAIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////" + "//////////////////////////////////////////////////8wgYgEQgH/////" + "////////////////////////////////////////////////////////////////" + "/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ" + "4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8ABIGFBADGhY4GtwQE6c2e" + "PstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5" + "fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQm" + "QMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////////////" + "////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool160r1", + "-----BEGIN EC PARAMETERS-----" + "MIGYAgEBMCAGByqGSM49AQECFQDpXkpfc3BZ3GDfx62Vs9gTlRViDzAsBBQ0Dnvi" + "ooDrdOK+YbradF2X6PfDAAQUHliahZVCNBITT6otveyVyNhnXlgEKQS+1a8W6j9q" + "T2KTjEYx61r3vbzbwxZny0d6Go7DOPlHQWacl2MW2mMhAhUA6V5KX3NwWdxg31mR" + "1FApQJ5g/AkCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool192r1", + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQDDAvQdkyo2zaejRjCT0Y23j85HbeGoYpcwNAQY" + "apEXQHax4OGcOcAx/oaFwcrgQOXGmijvBBhGmijvfCjMo9xyHQRPRJa8yn70FG+/" + "JckEMQTAoGR+qrakh1OwM8VssPCQCi9cSFM3X9YUtpCGar1buItfSCjBSQAC5nc/" + "ovopm48CGQDDAvQdkyo2zaejRi+enpFrW+jxAprErMECAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool224r1", + "-----BEGIN EC PARAMETERS-----" + "MIHIAgEBMCgGByqGSM49AQECHQDXwTSqJkNmhioYMCV10deHsJ8HV5faifV+yMD/" + "MDwEHGil5iypzmwcKZgDpsFTC1FOGCrYsAQqWcrSn0MEHCWA9jzP5EE4hwcTsakj" + "aeM+ITXSZtuzcjhsQAsEOQQNkCmtLH5c9DQII7KofcaMnkzjF0webv3uEsB9WKpW" + "93LAcm8kxrieTs2sJDVLnpnKo/bTdhQCzQIdANfBNKomQ2aGKhgwJXXQ+5jRFrxL" + "bd68o6Wnk58CAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool256r1", + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQCp+1fboe6pvD5mCpCdg41ybjv2I9UmICggE0gd" + "H25TdzBEBCB9Wgl1/CwwV+72dTBBev/n+4BVwSbcXGzpSktE8zC12QQgJtxcbOlK" + "S0TzMLXZu9d8v5WEFilc9+HOa8zcGP+MB7YEQQSL0q65y35XyyxLSC/8gbevud4n" + "4eO9I8I6RFO9ms4yYlR++DXD2sT9l/hGGhRhHcnCd0UTLe2OVFwdVMcvBGmXAiEA" + "qftX26Huqbw+ZgqQnYONcYw5eqO1Yab3kB4OgpdIVqcCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool320r1", + "-----BEGIN EC PARAMETERS-----" + "MIIBEAIBATA0BgcqhkjOPQEBAikA015HIDa8T7fhPHhe0gHgZfmPz6b29A3vT5K5" + "7HiT7Cj81BKx8bMuJzBUBCg+4wtWj7qw+IPM69RtPzu4oqc1E/XredpmGQ6whf+p" + "9JLzdal9hg60BChSCIOUnf28QtOtGYZAaIpv4T9BNJVUtJrMMdzNiEU5gW9etKyP" + "sfGmBFEEQ71+mvtT2LhSibzEjuW/5vIBN9EKCH6254ceKhClmccQr40NOeIGERT9" + "0FVF7BzIq0CTJH93J14HQ//tEXGC6qnHeHeqrGrH01JF0WkujuECKQDTXkcgNrxP" + "t+E8eF7SAeBl+Y/PpbaPEqMtSC7H7oZY6YaRVVtExZMRAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool384r1", + "-----BEGIN EC PARAMETERS-----" + "MIIBQAIBATA8BgcqhkjOPQEBAjEAjLkegqM4bSgPXW9+UOZB3xUvcQntVFa0ErHa" + "GX+3ESOs06cpkB0acYdHABMxB+xTMGQEMHvDgsY9jBUMPHIICs4Fr6DCvqKOT7In" + "hxORZe+6kfkPiqWBSlA61OsEqMfdIs4oJgQwBKjH3SLOKCaLObVUFvBEfC+3feEH" + "3NKmLogOpT7rYtV8tDkCldvJlDq3hpb6UEwRBGEEHRxk8GjPRf+ipjqBt8E/a4hH" + "o+d+8U/j23/K/gy9EOjoJuA0NtZGqu+HsuJH1K8eir4ddSD5wqRcseuOlc/VUmK3" + "Cyn+7Fhk4ZwFT/mRKSgORkYhd5GBEUKCA0EmPFMVAjEAjLkegqM4bSgPXW9+UOZB" + "3xUvcQntVFazHxZubKwEJafPOrava3/DEDuIMgLpBGVlAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "brainpool512r1", + "-----BEGIN EC PARAMETERS-----" + "MIIBogIBATBMBgcqhkjOPQEBAkEAqt2duNvpxIs/1OauM8n8B8swjbOzydIO1mOc" + "ynAzCHF9TZsAm8ZoQq7NoSrmo4DmKIH/Ly2CxoUoqmBWWDpI8zCBhARAeDCjMYtg" + "O4niMnFFrCNMxZTL3Y09+RYQqDRByuqYY7wt7V1aqCU6oQou8cmLmsi1fxEXpyvy" + "x7nnwaxNd/yUygRAPfkWEKg0QcrqmGO8Le1dWqglOqEKLvHJi5rItX8RF6cr8se5" + "58GsTXf8lMrcCD5nmEBQt1665d0oCb1jgBb3IwSBgQSBruS92C7ZZFohMi6cTGqT" + "he2fcLXZFsG0O2Lu9NAJjv87H3ji0NSNUNFoe5O5fV98bVBHQGpeaIs1Igm8ufgi" + "fd44XVZjMuzA6r+pz3gi/fIJ9wAkpXsaoADFW4gfgRGy3N5JSl9IXlvKS9iKJ2Ou" + "0corL6jwVAZ4zR4POtgIkgJBAKrdnbjb6cSLP9TmrjPJ/AfLMI2zs8nSDtZjnMpw" + "MwhwVT5cQUypJhlBhmEZf6wQRx2x04EIXdrdtYeWgpypAGkCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "x962_p192v2", + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBjMItbfuVxrJeScDWNkpOWYDDk6ohZo" + "2VMEMQTuorrn4Ul4QvLed2nP6cmJwHKtaW9IA0pldNEdabbsemcruCoIPfLysIR9" + "6XCy3hUCGQD///////////////5fsack3IBBhkjY3TECAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "x962_p192v3", + "-----BEGIN EC PARAMETERS-----" + "MIGwAgEBMCQGByqGSM49AQECGQD////////////////////+//////////8wNAQY" + "/////////////////////v/////////8BBgiEj3COVoFyqdCPa7MyUdgp9RiJWvV" + "aRYEMQR9KXeBAMZaHaF4NxZYjc4ri0rujiKPGJY4qQ8iY3M3M0tJ3LZqbcj5l4rK" + "dkipQ7ACGQD///////////////96YtAxyD9ClPZA7BMCAQE=" + "-----END EC PARAMETERS-----"); + + config.set("ec", "x962_p239v1", + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHmsBbDvc8YlB0NZU" + "khR1ynGp2y+yfR03eWGFwpQsCgQ9BA/6ljzcqIFszDO4ZCvt+QXD01hXPT8n+707" + "PLmqr33r6OTpCl2ubkBUylMLoEZUs2gYziJrOfzLewLxrgIef///////////////" + "f///nl6an12QcfvRUiaIkJ0LAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "x962_p239v2", + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHmF/q2gyV2y7/tUN" + "mfAknD/uWLlLoAOMeuhMjIMvLAQ9BDivCdmHJ3BRIMkhu16eJilqPNzy81dXoOr9" + "h7gw51sBJeTb6g7HIG2g/AHZsIEyn7VV3m70YCN9/4vkugIef///////////////" + "gAAAz6foWUN31BTAOCG8WCBjAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "x962_p239v3", + "-----BEGIN EC PARAMETERS-----" + "MIHSAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAAAAAH//////" + "/zBABB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZUsfTL" + "A9anUKMMJQEC1JiHF9m6FattPgQ9BGdoro4Yu5LPzwBclJqixtlIU9DmYLv4VLHJ" + "UF/pWhYH5omPOQwGvB1VK60ibztvz+SLboGEma8Y4+1s8wIef///////////////" + "f///l13rQbOmBXw8QyFGUmVRAgEB" + "-----END EC PARAMETERS-----"); + + config.set("ec", "gost_256A", + "-----BEGIN EC PARAMETERS-----" + "MIHgAgEBMCwGByqGSM49AQECIQD/////////////////////////////////////" + "///9lzBEBCD////////////////////////////////////////9lAQgAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYEQQQAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAY2R5HHgmJzaJ99QWkU/K3Y1KU8t3yPjsSKsyZyenx4UAiEA" + "/////////////////////2xhEHCZWtEARYQbCbdhuJMCAQE=" + "-----END EC PARAMETERS-----"); + } +} + +/* +* Set the default policy +*/ +void Library_State::load_default_config() + { + set_default_aliases(*this); + set_default_oids(*this); + set_default_dl_groups(*this); + } + +} +/* +* SCAN Name Abstraction +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +std::string make_arg( + const std::vector >& name, size_t start) + { + std::string output = name[start].second; + size_t level = name[start].first; + + size_t paren_depth = 0; + + for(size_t i = start + 1; i != name.size(); ++i) + { + if(name[i].first <= name[start].first) + break; + + if(name[i].first > level) + { + output += '(' + name[i].second; + ++paren_depth; + } + else if(name[i].first < level) + { + output += ")," + name[i].second; + --paren_depth; + } + else + { + if(output[output.size() - 1] != '(') + output += ","; + output += name[i].second; + } + + level = name[i].first; + } + + for(size_t i = 0; i != paren_depth; ++i) + output += ')'; + + return output; + } + +std::pair +deref_aliases(const std::pair& in) + { + return std::make_pair(in.first, + global_state().deref_alias(in.second)); + } + +} + +SCAN_Name::SCAN_Name(std::string algo_spec) + { + orig_algo_spec = algo_spec; + + std::vector > name; + size_t level = 0; + std::pair accum = std::make_pair(level, ""); + + std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + + algo_spec = global_state().deref_alias(algo_spec); + + for(size_t i = 0; i != algo_spec.size(); ++i) + { + char c = algo_spec[i]; + + if(c == '/' || c == ',' || c == '(' || c == ')') + { + if(c == '(') + ++level; + else if(c == ')') + { + if(level == 0) + throw Decoding_Error(decoding_error + "Mismatched parens"); + --level; + } + + if(c == '/' && level > 0) + accum.second.push_back(c); + else + { + if(accum.second != "") + name.push_back(deref_aliases(accum)); + accum = std::make_pair(level, ""); + } + } + else + accum.second.push_back(c); + } + + if(accum.second != "") + name.push_back(deref_aliases(accum)); + + if(level != 0) + throw Decoding_Error(decoding_error + "Missing close paren"); + + if(name.size() == 0) + throw Decoding_Error(decoding_error + "Empty name"); + + alg_name = name[0].second; + + bool in_modes = false; + + for(size_t i = 1; i != name.size(); ++i) + { + if(name[i].first == 0) + { + mode_info.push_back(make_arg(name, i)); + in_modes = true; + } + else if(name[i].first == 1 && !in_modes) + args.push_back(make_arg(name, i)); + } + } + +std::string SCAN_Name::algo_name_and_args() const + { + std::string out; + + out = algo_name(); + + if(arg_count()) + { + out += '('; + for(size_t i = 0; i != arg_count(); ++i) + { + out += arg(i); + if(i != arg_count() - 1) + out += ','; + } + out += ')'; + + } + + return out; + } + +std::string SCAN_Name::arg(size_t i) const + { + if(i >= arg_count()) + throw std::range_error("SCAN_Name::argument - i out of range"); + return args[i]; + } + +std::string SCAN_Name::arg(size_t i, const std::string& def_value) const + { + if(i >= arg_count()) + return def_value; + return args[i]; + } + +size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const + { + if(i >= arg_count()) + return def_value; + return to_u32bit(args[i]); + } + +} +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Update an CBC-MAC Calculation +*/ +void CBC_MAC::add_data(const byte input[], size_t length) + { + size_t xored = std::min(output_length() - position, length); + xor_buf(&state[position], input, xored); + position += xored; + + if(position < output_length()) + return; + + e->encrypt(state); + input += xored; + length -= xored; + while(length >= output_length()) + { + xor_buf(state, input, output_length()); + e->encrypt(state); + input += output_length(); + length -= output_length(); + } + + xor_buf(state, input, length); + position = length; + } + +/* +* Finalize an CBC-MAC Calculation +*/ +void CBC_MAC::final_result(byte mac[]) + { + if(position) + e->encrypt(state); + + copy_mem(mac, &state[0], state.size()); + zeroise(state); + position = 0; + } + +/* +* CBC-MAC Key Schedule +*/ +void CBC_MAC::key_schedule(const byte key[], size_t length) + { + e->set_key(key, length); + } + +/* +* Clear memory of sensitive data +*/ +void CBC_MAC::clear() + { + e->clear(); + zeroise(state); + position = 0; + } + +/* +* Return the name of this type +*/ +std::string CBC_MAC::name() const + { + return "CBC-MAC(" + e->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CBC_MAC::clone() const + { + return new CBC_MAC(e->clone()); + } + +/* +* CBC-MAC Constructor +*/ +CBC_MAC::CBC_MAC(BlockCipher* e_in) : + e(e_in), state(e->block_size()) + { + position = 0; + } + +/* +* CBC-MAC Destructor +*/ +CBC_MAC::~CBC_MAC() + { + delete e; + } + +} +/* +* CMAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Perform CMAC's multiplication in GF(2^n) +*/ +SecureVector CMAC::poly_double(const MemoryRegion& in, + byte polynomial) + { + const byte poly_xor = (in[0] & 0x80) ? polynomial : 0; + + SecureVector out = in; + + byte carry = 0; + for(size_t i = out.size(); i != 0; --i) + { + byte temp = out[i-1]; + out[i-1] = (temp << 1) | carry; + carry = (temp >> 7); + } + + out[out.size()-1] ^= poly_xor; + + return out; + } + +/* +* Update an CMAC Calculation +*/ +void CMAC::add_data(const byte input[], size_t length) + { + buffer.copy(position, input, length); + if(position + length > output_length()) + { + xor_buf(state, buffer, output_length()); + e->encrypt(state); + input += (output_length() - position); + length -= (output_length() - position); + while(length > output_length()) + { + xor_buf(state, input, output_length()); + e->encrypt(state); + input += output_length(); + length -= output_length(); + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/* +* Finalize an CMAC Calculation +*/ +void CMAC::final_result(byte mac[]) + { + xor_buf(state, buffer, position); + + if(position == output_length()) + { + xor_buf(state, B, output_length()); + } + else + { + state[position] ^= 0x80; + xor_buf(state, P, output_length()); + } + + e->encrypt(state); + + for(size_t i = 0; i != output_length(); ++i) + mac[i] = state[i]; + + zeroise(state); + zeroise(buffer); + position = 0; + } + +/* +* CMAC Key Schedule +*/ +void CMAC::key_schedule(const byte key[], size_t length) + { + clear(); + e->set_key(key, length); + e->encrypt(B); + B = poly_double(B, polynomial); + P = poly_double(B, polynomial); + } + +/* +* Clear memory of sensitive data +*/ +void CMAC::clear() + { + e->clear(); + zeroise(state); + zeroise(buffer); + zeroise(B); + zeroise(P); + position = 0; + } + +/* +* Return the name of this type +*/ +std::string CMAC::name() const + { + return "CMAC(" + e->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CMAC::clone() const + { + return new CMAC(e->clone()); + } + +/* +* CMAC Constructor +*/ +CMAC::CMAC(BlockCipher* e_in) : e(e_in) + { + if(e->block_size() == 16) + polynomial = 0x87; + else if(e->block_size() == 8) + polynomial = 0x1B; + else + throw Invalid_Argument("CMAC cannot use the cipher " + e->name()); + + state.resize(output_length()); + buffer.resize(output_length()); + B.resize(output_length()); + P.resize(output_length()); + position = 0; + } + +/* +* CMAC Destructor +*/ +CMAC::~CMAC() + { + delete e; + } + +} +/* +* HMAC +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Update a HMAC Calculation +*/ +void HMAC::add_data(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Finalize a HMAC Calculation +*/ +void HMAC::final_result(byte mac[]) + { + hash->final(mac); + hash->update(o_key); + hash->update(mac, output_length()); + hash->final(mac); + hash->update(i_key); + } + +/* +* HMAC Key Schedule +*/ +void HMAC::key_schedule(const byte key[], size_t length) + { + hash->clear(); + std::fill(i_key.begin(), i_key.end(), 0x36); + std::fill(o_key.begin(), o_key.end(), 0x5C); + + if(length > hash->hash_block_size()) + { + SecureVector hmac_key = hash->process(key, length); + xor_buf(i_key, hmac_key, hmac_key.size()); + xor_buf(o_key, hmac_key, hmac_key.size()); + } + else + { + xor_buf(i_key, key, length); + xor_buf(o_key, key, length); + } + + hash->update(i_key); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC::clear() + { + hash->clear(); + zeroise(i_key); + zeroise(o_key); + } + +/* +* Return the name of this type +*/ +std::string HMAC::name() const + { + return "HMAC(" + hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* HMAC::clone() const + { + return new HMAC(hash->clone()); + } + +/* +* HMAC Constructor +*/ +HMAC::HMAC(HashFunction* hash_in) : hash(hash_in) + { + if(hash->hash_block_size() == 0) + throw Invalid_Argument("HMAC cannot be used with " + hash->name()); + + i_key.resize(hash->hash_block_size()); + o_key.resize(hash->hash_block_size()); + } + +} +/* +* Message Authentication Code base class +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Default (deterministic) MAC verification operation +*/ +bool MessageAuthenticationCode::verify_mac(const byte mac[], size_t length) + { + SecureVector our_mac = final(); + + if(our_mac.size() != length) + return false; + + return same_mem(&our_mac[0], &mac[0], length); + } + +} +/* +* SSL3-MAC +* (C) 1999-2004 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Update a SSL3-MAC Calculation +*/ +void SSL3_MAC::add_data(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Finalize a SSL3-MAC Calculation +*/ +void SSL3_MAC::final_result(byte mac[]) + { + hash->final(mac); + hash->update(o_key); + hash->update(mac, output_length()); + hash->final(mac); + hash->update(i_key); + } + +/* +* SSL3-MAC Key Schedule +*/ +void SSL3_MAC::key_schedule(const byte key[], size_t length) + { + hash->clear(); + std::fill(i_key.begin(), i_key.end(), 0x36); + std::fill(o_key.begin(), o_key.end(), 0x5C); + + i_key.copy(key, length); + o_key.copy(key, length); + hash->update(i_key); + } + +/* +* Clear memory of sensitive data +*/ +void SSL3_MAC::clear() + { + hash->clear(); + zeroise(i_key); + zeroise(o_key); + } + +/* +* Return the name of this type +*/ +std::string SSL3_MAC::name() const + { + return "SSL3-MAC(" + hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* SSL3_MAC::clone() const + { + return new SSL3_MAC(hash->clone()); + } + +/* +* SSL3-MAC Constructor +*/ +SSL3_MAC::SSL3_MAC(HashFunction* hash_in) : hash(hash_in) + { + if(hash->hash_block_size() == 0) + throw Invalid_Argument("SSL3-MAC cannot be used with " + hash->name()); + + // Quirk to deal with specification bug + const size_t INNER_HASH_LENGTH = + (hash->name() == "SHA-160") ? 60 : hash->hash_block_size(); + + i_key.resize(INNER_HASH_LENGTH); + o_key.resize(INNER_HASH_LENGTH); + } + +} +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Update an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::add_data(const byte input[], size_t length) + { + size_t xored = std::min(8 - position, length); + xor_buf(&state[position], input, xored); + position += xored; + + if(position < 8) return; + + e->encrypt(state); + input += xored; + length -= xored; + while(length >= 8) + { + xor_buf(state, input, 8); + e->encrypt(state); + input += 8; + length -= 8; + } + + xor_buf(state, input, length); + position = length; + } + +/* +* Finalize an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::final_result(byte mac[]) + { + if(position) + e->encrypt(state); + d->decrypt(state, mac); + e->encrypt(mac); + zeroise(state); + position = 0; + } + +/* +* ANSI X9.19 MAC Key Schedule +*/ +void ANSI_X919_MAC::key_schedule(const byte key[], size_t length) + { + e->set_key(key, 8); + if(length == 8) d->set_key(key, 8); + else d->set_key(key + 8, 8); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X919_MAC::clear() + { + e->clear(); + d->clear(); + zeroise(state); + position = 0; + } + +std::string ANSI_X919_MAC::name() const + { + return "X9.19-MAC"; + } + +MessageAuthenticationCode* ANSI_X919_MAC::clone() const + { + return new ANSI_X919_MAC(e->clone()); + } + +/* +* ANSI X9.19 MAC Constructor +*/ +ANSI_X919_MAC::ANSI_X919_MAC(BlockCipher* e_in) : + e(e_in), d(e->clone()), state(e->block_size()), position(0) + { + if(e->name() != "DES") + throw Invalid_Argument("ANSI X9.19 MAC only supports DES"); + } + +/* +* ANSI X9.19 MAC Destructor +le*/ +ANSI_X919_MAC::~ANSI_X919_MAC() + { + delete e; + delete d; + } + +} +/* +* BigInt Encoding/Decoding +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Encode a BigInt +*/ +void BigInt::encode(byte output[], const BigInt& n, Base base) + { + if(base == Binary) + n.binary_encode(output); + else if(base == Hexadecimal) + { + SecureVector binary(n.encoded_size(Binary)); + n.binary_encode(&binary[0]); + + hex_encode(reinterpret_cast(output), + &binary[0], binary.size()); + } + else if(base == Octal) + { + BigInt copy = n; + const size_t output_size = n.encoded_size(Octal); + for(size_t j = 0; j != output_size; ++j) + { + output[output_size - 1 - j] = + Charset::digit2char(static_cast(copy % 8)); + + copy /= 8; + } + } + else if(base == Decimal) + { + BigInt copy = n; + BigInt remainder; + copy.set_sign(Positive); + const size_t output_size = n.encoded_size(Decimal); + for(size_t j = 0; j != output_size; ++j) + { + divide(copy, 10, copy, remainder); + output[output_size - 1 - j] = + Charset::digit2char(static_cast(remainder.word_at(0))); + if(copy.is_zero()) + break; + } + } + else + throw Invalid_Argument("Unknown BigInt encoding method"); + } + +/* +* Encode a BigInt +*/ +SecureVector BigInt::encode(const BigInt& n, Base base) + { + SecureVector output(n.encoded_size(base)); + encode(&output[0], n, base); + if(base != Binary) + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/* +* Encode a BigInt, with leading 0s if needed +*/ +SecureVector BigInt::encode_1363(const BigInt& n, size_t bytes) + { + const size_t n_bytes = n.bytes(); + if(n_bytes > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + const size_t leading_0s = bytes - n_bytes; + + SecureVector output(bytes); + encode(&output[leading_0s], n, Binary); + return output; + } + +/* +* Decode a BigInt +*/ +BigInt BigInt::decode(const MemoryRegion& buf, Base base) + { + return BigInt::decode(&buf[0], buf.size(), base); + } + +/* +* Decode a BigInt +*/ +BigInt BigInt::decode(const byte buf[], size_t length, Base base) + { + BigInt r; + if(base == Binary) + r.binary_decode(buf, length); + else if(base == Hexadecimal) + { + SecureVector binary; + const char *cbuf = reinterpret_cast(buf); + + if(length % 2) + { + // Handle lack of leading 0 + const char buf0_with_leading_0[2] = { '0', cbuf[0] }; + binary = hex_decode(buf0_with_leading_0, 2); + + binary += hex_decode(&cbuf[1], length - 1, false); + } + else + binary = hex_decode(cbuf, length, false); + + r.binary_decode(&binary[0], binary.size()); + } + else if(base == Decimal || base == Octal) + { + const size_t RADIX = ((base == Decimal) ? 10 : 8); + for(size_t j = 0; j != length; ++j) + { + if(Charset::is_space(buf[j])) + continue; + + if(!Charset::is_digit(buf[j])) + throw Invalid_Argument("BigInt::decode: " + "Invalid character in decimal input"); + + byte x = Charset::char2digit(buf[j]); + if(x >= RADIX) + { + if(RADIX == 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + else + throw Invalid_Argument("BigInt: Invalid octal string"); + } + + r *= RADIX; + r += x; + } + } + else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; + } + +} +/* +* BigInt Input/Output +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Write the BigInt into a stream +*/ +std::ostream& operator<<(std::ostream& stream, const BigInt& n) + { + BigInt::Base base = BigInt::Decimal; + if(stream.flags() & std::ios::hex) + base = BigInt::Hexadecimal; + else if(stream.flags() & std::ios::oct) + base = BigInt::Octal; + + if(n == 0) + stream.write("0", 1); + else + { + if(n < 0) + stream.write("-", 1); + SecureVector buffer = BigInt::encode(n, base); + size_t skip = 0; + while(buffer[skip] == '0' && skip < buffer.size()) + ++skip; + stream.write(reinterpret_cast(&buffer[0]) + skip, + buffer.size() - skip); + } + if(!stream.good()) + throw Stream_IO_Error("BigInt output operator has failed"); + return stream; + } + +/* +* Read the BigInt from a stream +*/ +std::istream& operator>>(std::istream& stream, BigInt& n) + { + std::string str; + std::getline(stream, str); + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("BigInt input operator has failed"); + n = BigInt(str); + return stream; + } + +} +/* +* BigInt Assignment Operators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Addition Operator +*/ +BigInt& BigInt::operator+=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + + const size_t reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(sign() == y.sign()) + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + else + { + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + if(relative_size < 0) + { + SecureVector z(reg_size - 1); + bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); + copy_mem(®[0], &z[0], z.size()); + set_sign(y.sign()); + } + else if(relative_size == 0) + { + zeroise(reg); + set_sign(Positive); + } + else if(relative_size > 0) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + } + + return (*this); + } + +/* +* Subtraction Operator +*/ +BigInt& BigInt::operator-=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + const size_t reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(relative_size < 0) + { + if(sign() == y.sign()) + bigint_sub2_rev(get_reg(), y.data(), y_sw); + else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + + set_sign(y.reverse_sign()); + } + else if(relative_size == 0) + { + if(sign() == y.sign()) + { + clear(); + set_sign(Positive); + } + else + bigint_shl1(get_reg(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(sign() == y.sign()) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + } + + return (*this); + } + +/* +* Multiplication Operator +*/ +BigInt& BigInt::operator*=(const BigInt& y) + { + const size_t x_sw = sig_words(), y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if(x_sw == 0 || y_sw == 0) + { + clear(); + set_sign(Positive); + } + else if(x_sw == 1 && y_sw) + { + grow_to(y_sw + 2); + bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0)); + } + else if(y_sw == 1 && x_sw) + { + grow_to(x_sw + 2); + bigint_linmul2(get_reg(), x_sw, y.word_at(0)); + } + else + { + grow_to(size() + y.size()); + + SecureVector z(data(), x_sw); + SecureVector workspace(size()); + + bigint_mul(get_reg(), size(), workspace, + z, z.size(), x_sw, + y.data(), y.size(), y_sw); + } + + return (*this); + } + +/* +* Division Operator +*/ +BigInt& BigInt::operator/=(const BigInt& y) + { + if(y.sig_words() == 1 && power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); + } + +/* +* Modulo Operator +*/ +BigInt& BigInt::operator%=(const BigInt& mod) + { + return (*this = (*this) % mod); + } + +/* +* Modulo Operator +*/ +word BigInt::operator%=(word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + if(power_of_2(mod)) + { + word result = (word_at(0) & (mod - 1)); + clear(); + grow_to(2); + get_reg()[0] = result; + return result; + } + + word remainder = 0; + + for(size_t j = sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, word_at(j-1), mod); + clear(); + grow_to(2); + + if(remainder && sign() == BigInt::Negative) + get_reg()[0] = mod - remainder; + else + get_reg()[0] = remainder; + + set_sign(BigInt::Positive); + + return word_at(0); + } + +/* +* Left Shift Operator +*/ +BigInt& BigInt::operator<<=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS, + words = sig_words(); + + grow_to(words + shift_words + (shift_bits ? 1 : 0)); + bigint_shl1(get_reg(), words, shift_words, shift_bits); + } + + return (*this); + } + +/* +* Right Shift Operator +*/ +BigInt& BigInt::operator>>=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits); + + if(is_zero()) + set_sign(Positive); + } + + return (*this); + } + +} +/* +* BigInt Binary Operators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Addition Operator +*/ +BigInt operator+(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); + + if((x.sign() == y.sign())) + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + else + { + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + + if(relative_size < 0) + { + bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); + z.set_sign(y.sign()); + } + else if(relative_size == 0) + z.set_sign(BigInt::Positive); + else if(relative_size > 0) + bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + } + + return z; + } + +/* +* Subtraction Operator +*/ +BigInt operator-(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + + BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); + + if(relative_size < 0) + { + if(x.sign() == y.sign()) + bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); + else + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(y.reverse_sign()); + } + else if(relative_size == 0) + { + if(x.sign() != y.sign()) + bigint_shl2(z.get_reg(), x.data(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(x.sign() == y.sign()) + bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + else + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(x.sign()); + } + return z; + } + +/* +* Multiplication Operator +*/ +BigInt operator*(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(BigInt::Positive, x.size() + y.size()); + + if(x_sw == 1 && y_sw) + bigint_linmul3(z.get_reg(), y.data(), y_sw, x.word_at(0)); + else if(y_sw == 1 && x_sw) + bigint_linmul3(z.get_reg(), x.data(), x_sw, y.word_at(0)); + else if(x_sw && y_sw) + { + SecureVector workspace(z.size()); + bigint_mul(z.get_reg(), z.size(), workspace, + x.data(), x.size(), x_sw, + y.data(), y.size(), y_sw); + } + + if(x_sw && y_sw && x.sign() != y.sign()) + z.flip_sign(); + return z; + } + +/* +* Division Operator +*/ +BigInt operator/(const BigInt& x, const BigInt& y) + { + BigInt q, r; + divide(x, y, q, r); + return q; + } + +/* +* Modulo Operator +*/ +BigInt operator%(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative()) + throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); + if(n.is_positive() && mod.is_positive() && n < mod) + return n; + + BigInt q, r; + divide(n, mod, q, r); + return r; + } + +/* +* Modulo Operator +*/ +word operator%(const BigInt& n, word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + if(power_of_2(mod)) + return (n.word_at(0) & (mod - 1)); + + word remainder = 0; + + for(size_t j = n.sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, n.word_at(j-1), mod); + + if(remainder && n.sign() == BigInt::Negative) + return mod - remainder; + return remainder; + } + +/* +* Left Shift Operator +*/ +BigInt operator<<(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + const size_t x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +/* +* Right Shift Operator +*/ +BigInt operator>>(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + if(x.bits() <= shift) + return 0; + + const size_t shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS, + x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw - shift_words); + bigint_shr2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +} +/* +* BigInt Random Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Construct a BigInt of a specific form +*/ +BigInt::BigInt(NumberType type, size_t bits) + { + set_sign(Positive); + + if(type == Power2) + set_bit(bits); + else + throw Invalid_Argument("BigInt(NumberType): Unknown type"); + } + +/* +* Randomize this number +*/ +void BigInt::randomize(RandomNumberGenerator& rng, + size_t bitsize) + { + set_sign(Positive); + + if(bitsize == 0) + clear(); + else + { + SecureVector array = rng.random_vec((bitsize + 7) / 8); + + if(bitsize % 8) + array[0] &= 0xFF >> (8 - (bitsize % 8)); + array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); + binary_decode(&array[0], array.size()); + } + } + +/* +* Generate a random integer within given range +*/ +BigInt BigInt::random_integer(RandomNumberGenerator& rng, + const BigInt& min, const BigInt& max) + { + BigInt range = max - min; + + if(range <= 0) + throw Invalid_Argument("random_integer: invalid min/max values"); + + return (min + (BigInt(rng, range.bits() + 2) % range)); + } + +} +/* +* BigInt Base +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Construct a BigInt from a regular number +*/ +BigInt::BigInt(u64bit n) + { + set_sign(Positive); + + if(n == 0) + return; + + const size_t limbs_needed = sizeof(u64bit) / sizeof(word); + + reg.resize(4*limbs_needed); + for(size_t i = 0; i != limbs_needed; ++i) + reg[i] = ((n >> (i*MP_WORD_BITS)) & MP_WORD_MASK); + } + +/* +* Construct a BigInt of the specified size +*/ +BigInt::BigInt(Sign s, size_t size) + { + reg.resize(round_up(size, 8)); + signedness = s; + } + +/* +* Construct a BigInt from a "raw" BigInt +*/ +BigInt::BigInt(const BigInt& b) + { + const size_t b_words = b.sig_words(); + + if(b_words) + { + reg.resize(round_up(b_words, 8)); + reg.copy(b.data(), b_words); + set_sign(b.sign()); + } + else + { + reg.resize(2); + set_sign(Positive); + } + } + +/* +* Construct a BigInt from a string +*/ +BigInt::BigInt(const std::string& str) + { + Base base = Decimal; + size_t markers = 0; + bool negative = false; + if(str.length() > 0 && str[0] == '-') { markers += 1; negative = true; } + + if(str.length() > markers + 2 && str[markers ] == '0' && + str[markers + 1] == 'x') + { markers += 2; base = Hexadecimal; } + else if(str.length() > markers + 1 && str[markers] == '0') + { markers += 1; base = Octal; } + + *this = decode(reinterpret_cast(str.data()) + markers, + str.length() - markers, base); + + if(negative) set_sign(Negative); + else set_sign(Positive); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(const byte input[], size_t length, Base base) + { + set_sign(Positive); + *this = decode(input, length, base); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(RandomNumberGenerator& rng, size_t bits) + { + set_sign(Positive); + randomize(rng, bits); + } + +/* +* Swap this BigInt with another +*/ +void BigInt::swap(BigInt& other) + { + reg.swap(other.reg); + std::swap(signedness, other.signedness); + } + +/* +* Grow the internal storage +*/ +void BigInt::grow_reg(size_t n) + { + reg.resize(round_up(size() + n, 8)); + } + +/* +* Grow the internal storage +*/ +void BigInt::grow_to(size_t n) + { + if(n > size()) + reg.resize(round_up(n, 8)); + } + +/* +* Comparison Function +*/ +s32bit BigInt::cmp(const BigInt& n, bool check_signs) const + { + if(check_signs) + { + if(n.is_positive() && this->is_negative()) return -1; + if(n.is_negative() && this->is_positive()) return 1; + if(n.is_negative() && this->is_negative()) + return (-bigint_cmp(data(), sig_words(), n.data(), n.sig_words())); + } + return bigint_cmp(data(), sig_words(), n.data(), n.sig_words()); + } + +/* +* Return byte n of this number +*/ +byte BigInt::byte_at(size_t n) const + { + const size_t WORD_BYTES = sizeof(word); + size_t word_num = n / WORD_BYTES, byte_num = n % WORD_BYTES; + if(word_num >= size()) + return 0; + else + return get_byte(WORD_BYTES - byte_num - 1, reg[word_num]); + } + +/* +* Return bit n of this number +*/ +bool BigInt::get_bit(size_t n) const + { + return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1); + } + +/* +* Return bits {offset...offset+length} +*/ +u32bit BigInt::get_substring(size_t offset, size_t length) const + { + if(length > 32) + throw Invalid_Argument("BigInt::get_substring: Substring size too big"); + + u64bit piece = 0; + for(size_t i = 0; i != 8; ++i) + { + const byte part = byte_at((offset / 8) + (7-i)); + piece = (piece << 8) | part; + } + + const u64bit mask = (static_cast(1) << length) - 1; + const size_t shift = (offset % 8); + + return static_cast((piece >> shift) & mask); + } + +/* +* Convert this number to a u32bit, if possible +*/ +u32bit BigInt::to_u32bit() const + { + if(is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if(bits() >= 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + u32bit out = 0; + for(u32bit j = 0; j != 4; ++j) + out = (out << 8) | byte_at(3-j); + return out; + } + +/* +* Set bit number n +*/ +void BigInt::set_bit(size_t n) + { + const size_t which = n / MP_WORD_BITS; + const word mask = static_cast(1) << (n % MP_WORD_BITS); + if(which >= size()) grow_to(which + 1); + reg[which] |= mask; + } + +/* +* Clear bit number n +*/ +void BigInt::clear_bit(size_t n) + { + const size_t which = n / MP_WORD_BITS; + const word mask = static_cast(1) << (n % MP_WORD_BITS); + if(which < size()) + reg[which] &= ~mask; + } + +/* +* Clear all but the lowest n bits +*/ +void BigInt::mask_bits(size_t n) + { + if(n == 0) { clear(); return; } + if(n >= bits()) return; + + const size_t top_word = n / MP_WORD_BITS; + const word mask = (static_cast(1) << (n % MP_WORD_BITS)) - 1; + + if(top_word < size()) + for(size_t i = top_word + 1; i != size(); ++i) + reg[i] = 0; + + reg[top_word] &= mask; + } + +/* +* Count how many bytes are being used +*/ +size_t BigInt::bytes() const + { + return (bits() + 7) / 8; + } + +/* +* Count how many bits are being used +*/ +size_t BigInt::bits() const + { + const size_t words = sig_words(); + + if(words == 0) + return 0; + + size_t full_words = words - 1, top_bits = MP_WORD_BITS; + word top_word = word_at(full_words), mask = MP_WORD_TOP_BIT; + + while(top_bits && ((top_word & mask) == 0)) + { mask >>= 1; top_bits--; } + + return (full_words * MP_WORD_BITS + top_bits); + } + +/* +* Calcluate the size in a certain base +*/ +size_t BigInt::encoded_size(Base base) const + { + static const double LOG_2_BASE_10 = 0.30102999566; + + if(base == Binary) + return bytes(); + else if(base == Hexadecimal) + return 2*bytes(); + else if(base == Octal) + return ((bits() + 2) / 3); + else if(base == Decimal) + return static_cast((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); + } + +/* +* Set the sign +*/ +void BigInt::set_sign(Sign s) + { + if(is_zero()) + signedness = Positive; + else + signedness = s; + } + +/* +* Reverse the value of the sign flag +*/ +void BigInt::flip_sign() + { + set_sign(reverse_sign()); + } + +/* +* Return the opposite value of the current sign +*/ +BigInt::Sign BigInt::reverse_sign() const + { + if(sign() == Positive) + return Negative; + return Positive; + } + +/* +* Return the negation of this number +*/ +BigInt BigInt::operator-() const + { + BigInt x = (*this); + x.flip_sign(); + return x; + } + +/* +* Return the absolute value of this number +*/ +BigInt BigInt::abs() const + { + BigInt x = (*this); + x.set_sign(Positive); + return x; + } + +/* +* Encode this number into bytes +*/ +void BigInt::binary_encode(byte output[]) const + { + const size_t sig_bytes = bytes(); + for(size_t i = 0; i != sig_bytes; ++i) + output[sig_bytes-i-1] = byte_at(i); + } + +/* +* Set this number to the value in buf +*/ +void BigInt::binary_decode(const byte buf[], size_t length) + { + const size_t WORD_BYTES = sizeof(word); + + clear(); + reg.resize(round_up((length / WORD_BYTES) + 1, 8)); + + for(size_t i = 0; i != length / WORD_BYTES; ++i) + { + const size_t top = length - WORD_BYTES*i; + for(size_t j = WORD_BYTES; j > 0; --j) + reg[i] = (reg[i] << 8) | buf[top - j]; + } + + for(size_t i = 0; i != length % WORD_BYTES; ++i) + reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[i]; + } + +/* +* Set this number to the value in buf +*/ +void BigInt::binary_decode(const MemoryRegion& buf) + { + binary_decode(buf, buf.size()); + } + +} +/* +* Division Algorithm +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Handle signed operands, if necessary +*/ +void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) + { + if(x.sign() == BigInt::Negative) + { + q.flip_sign(); + if(r.is_nonzero()) { --q; r = y.abs() - r; } + } + if(y.sign() == BigInt::Negative) + q.flip_sign(); + } + +} + +/* +* Solve x = q * y + r +*/ +void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r) + { + if(y_arg.is_zero()) + throw BigInt::DivideByZero(); + + BigInt y = y_arg; + const size_t y_words = y.sig_words(); + + r = x; + q = 0; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + s32bit compare = r.cmp(y); + + if(compare == 0) + { + q = 1; + r = 0; + } + else if(compare > 0) + { + size_t shifts = 0; + word y_top = y[y.sig_words()-1]; + while(y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; } + y <<= shifts; + r <<= shifts; + + const size_t n = r.sig_words() - 1, t = y_words - 1; + + if(n < t) + throw Internal_Error("BigInt division word sizes"); + + q.get_reg().resize(n - t + 1); + if(n <= t) + { + while(r > y) { r -= y; ++q; } + r >>= shifts; + sign_fixup(x, y_arg, q, r); + return; + } + + BigInt temp = y << (MP_WORD_BITS * (n-t)); + + while(r >= temp) { r -= temp; ++q[n-t]; } + + for(size_t j = n; j != t; --j) + { + const word x_j0 = r.word_at(j); + const word x_j1 = r.word_at(j-1); + const word y_t = y.word_at(t); + + if(x_j0 == y_t) + q[j-t-1] = MP_WORD_MAX; + else + q[j-t-1] = bigint_divop(x_j0, x_j1, y_t); + + while(bigint_divcore(q[j-t-1], y_t, y.word_at(t-1), + x_j0, x_j1, r.word_at(j-2))) + --q[j-t-1]; + + r -= (q[j-t-1] * y) << (MP_WORD_BITS * (j-t-1)); + if(r.is_negative()) + { + r += y << (MP_WORD_BITS * (j-t-1)); + --q[j-t-1]; + } + } + r >>= shifts; + } + + sign_fixup(x, y_arg, q, r); + } + +} +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +PointGFp::PointGFp(const CurveGFp& curve) : + curve(curve), ws(2 * (curve.get_p_words() + 2)) + { + coord_x = 0; + coord_y = monty_mult(1, curve.get_r2()); + coord_z = 0; + } + +PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : + curve(curve), ws(2 * (curve.get_p_words() + 2)) + { + coord_x = monty_mult(x, curve.get_r2()); + coord_y = monty_mult(y, curve.get_r2()); + coord_z = monty_mult(1, curve.get_r2()); + } + +// Montgomery multiplication +void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const + { + //assert(&z != &x && &z != &y); + + if(x.is_zero() || y.is_zero()) + { + z = 0; + return; + } + + const BigInt& p = curve.get_p(); + const size_t p_size = curve.get_p_words(); + const word p_dash = curve.get_p_dash(); + + SecureVector& z_reg = z.get_reg(); + z_reg.resize(2*p_size+1); + zeroise(z_reg); + + bigint_monty_mul(&z_reg[0], z_reg.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); + } + +// Montgomery squaring +void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const + { + //assert(&z != &x); + + if(x.is_zero()) + { + z = 0; + return; + } + + const BigInt& p = curve.get_p(); + const size_t p_size = curve.get_p_words(); + const word p_dash = curve.get_p_dash(); + + SecureVector& z_reg = z.get_reg(); + z_reg.resize(2*p_size+1); + zeroise(z_reg); + + bigint_monty_sqr(&z_reg[0], z_reg.size(), + x.data(), x.size(), x.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); + } + +// Point addition +void PointGFp::add(const PointGFp& rhs, std::vector& ws_bn) + { + if(is_zero()) + { + coord_x = rhs.coord_x; + coord_y = rhs.coord_y; + coord_z = rhs.coord_z; + return; + } + else if(rhs.is_zero()) + return; + + const BigInt& p = curve.get_p(); + + BigInt& rhs_z2 = ws_bn[0]; + BigInt& U1 = ws_bn[1]; + BigInt& S1 = ws_bn[2]; + + BigInt& lhs_z2 = ws_bn[3]; + BigInt& U2 = ws_bn[4]; + BigInt& S2 = ws_bn[5]; + + BigInt& H = ws_bn[6]; + BigInt& r = ws_bn[7]; + + monty_sqr(rhs_z2, rhs.coord_z); + monty_mult(U1, coord_x, rhs_z2); + monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2)); + + monty_sqr(lhs_z2, coord_z); + monty_mult(U2, rhs.coord_x, lhs_z2); + monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2)); + + H = U2; + H -= U1; + if(H.is_negative()) + H += p; + + r = S2; + r -= S1; + if(r.is_negative()) + r += p; + + if(H.is_zero()) + { + if(r.is_zero()) + { + mult2(ws_bn); + return; + } + + *this = PointGFp(curve); // setting myself to zero + return; + } + + monty_sqr(U2, H); + + monty_mult(S2, U2, H); + + U2 = monty_mult(U1, U2); + + monty_sqr(coord_x, r); + coord_x -= S2; + coord_x -= (U2 << 1); + while(coord_x.is_negative()) + coord_x += p; + + U2 -= coord_x; + if(U2.is_negative()) + U2 += p; + + monty_mult(coord_y, r, U2); + coord_y -= monty_mult(S1, S2); + if(coord_y.is_negative()) + coord_y += p; + + monty_mult(coord_z, monty_mult(coord_z, rhs.coord_z), H); + } + +// *this *= 2 +void PointGFp::mult2(std::vector& ws_bn) + { + if(is_zero()) + return; + else if(coord_y.is_zero()) + { + *this = PointGFp(curve); // setting myself to zero + return; + } + + const BigInt& p = curve.get_p(); + + BigInt& y_2 = ws_bn[0]; + BigInt& S = ws_bn[1]; + BigInt& z4 = ws_bn[2]; + BigInt& a_z4 = ws_bn[3]; + BigInt& M = ws_bn[4]; + BigInt& U = ws_bn[5]; + BigInt& x = ws_bn[6]; + BigInt& y = ws_bn[7]; + BigInt& z = ws_bn[8]; + + monty_sqr(y_2, coord_y); + + monty_mult(S, coord_x, y_2); + S <<= 2; // * 4 + while(S >= p) + S -= p; + + monty_sqr(z4, monty_sqr(coord_z)); + monty_mult(a_z4, curve.get_a_r(), z4); + + M = 3 * monty_sqr(coord_x); + M += a_z4; + while(M >= p) + M -= p; + + monty_sqr(x, M); + x -= (S << 1); + while(x.is_negative()) + x += p; + + monty_sqr(U, y_2); + U <<= 3; + while(U >= p) + U -= p; + + S -= x; + while(S.is_negative()) + S += p; + + monty_mult(y, M, S); + y -= U; + if(y.is_negative()) + y += p; + + monty_mult(z, coord_y, coord_z); + z <<= 1; + if(z >= p) + z -= p; + + coord_x = x; + coord_y = y; + coord_z = z; + } + +// arithmetic operators +PointGFp& PointGFp::operator+=(const PointGFp& rhs) + { + std::vector ws(9); + add(rhs, ws); + return *this; + } + +PointGFp& PointGFp::operator-=(const PointGFp& rhs) + { + PointGFp minus_rhs = PointGFp(rhs).negate(); + + if(is_zero()) + *this = minus_rhs; + else + *this += minus_rhs; + + return *this; + } + +PointGFp& PointGFp::operator*=(const BigInt& scalar) + { + *this = scalar * *this; + return *this; + } + +PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2) + { + const PointGFp p3 = p1 + p2; + + PointGFp H(p1.curve); // create as zero + size_t bits_left = std::max(z1.bits(), z2.bits()); + + std::vector ws(9); + + while(bits_left) + { + H.mult2(ws); + + const bool z1_b = z1.get_bit(bits_left - 1); + const bool z2_b = z2.get_bit(bits_left - 1); + + if(z1_b == true && z2_b == true) + H.add(p3, ws); + else if(z1_b) + H.add(p1, ws); + else if(z2_b) + H.add(p2, ws); + + --bits_left; + } + + if(z1.is_negative() != z2.is_negative()) + H.negate(); + + return H; + } + +PointGFp operator*(const BigInt& scalar, const PointGFp& point) + { + const CurveGFp& curve = point.get_curve(); + + if(scalar.is_zero()) + return PointGFp(curve); // zero point + + std::vector ws(9); + + if(scalar.abs() <= 2) // special cases for small values + { + byte value = scalar.abs().byte_at(0); + + PointGFp result = point; + + if(value == 2) + result.mult2(ws); + + if(scalar.is_negative()) + result.negate(); + + return result; + } + + const size_t scalar_bits = scalar.bits(); + +#if 0 + + PointGFp x1 = PointGFp(curve); + PointGFp x2 = point; + + size_t bits_left = scalar_bits; + + // Montgomery Ladder + while(bits_left) + { + const bool bit_set = scalar.get_bit(bits_left - 1); + + if(bit_set) + { + x1.add(x2, ws); + x2.mult2(ws); + } + else + { + x2.add(x1, ws); + x1.mult2(ws); + } + + --bits_left; + } + + if(scalar.is_negative()) + x1.negate(); + + return x1; + +#else + const size_t window_size = 4; + + std::vector Ps(1 << window_size); + Ps[0] = PointGFp(curve); + Ps[1] = point; + + for(size_t i = 2; i != Ps.size(); ++i) + { + Ps[i] = Ps[i-1]; + Ps[i].add(point, ws); + } + + PointGFp H(curve); // create as zero + size_t bits_left = scalar_bits; + + while(bits_left >= window_size) + { + for(size_t i = 0; i != window_size; ++i) + H.mult2(ws); + + const u32bit nibble = scalar.get_substring(bits_left - window_size, + window_size); + + H.add(Ps[nibble], ws); + + bits_left -= window_size; + } + + while(bits_left) + { + H.mult2(ws); + if(scalar.get_bit(bits_left-1)) + H.add(point, ws); + + --bits_left; + } + + if(scalar.is_negative()) + H.negate(); + + return H; +#endif + } + +BigInt PointGFp::get_affine_x() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + const BigInt& r2 = curve.get_r2(); + + BigInt z2 = monty_sqr(coord_z); + z2 = inverse_mod(z2, curve.get_p()); + + z2 = monty_mult(z2, r2); + return monty_mult(coord_x, z2); + } + +BigInt PointGFp::get_affine_y() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + const BigInt& r2 = curve.get_r2(); + + BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z)); + z3 = inverse_mod(z3, curve.get_p()); + z3 = monty_mult(z3, r2); + return monty_mult(coord_y, z3); + } + +bool PointGFp::on_the_curve() const + { + /* + Is the point still on the curve?? (If everything is correct, the + point is always on its curve; then the function will return true. + If somehow the state is corrupted, which suggests a fault attack + (or internal computational error), then return false. + */ + + if(is_zero()) + return true; + + BigInt y2 = monty_mult(monty_sqr(coord_y), 1); + BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x)); + + BigInt ax = monty_mult(coord_x, curve.get_a_r()); + + const BigInt& b_r = curve.get_b_r(); + + BigInt z2 = monty_sqr(coord_z); + + if(coord_z == z2) // Is z equal to 1 (in Montgomery form)? + { + if(y2 != monty_mult(x3 + ax + b_r, 1)) + return false; + } + + BigInt z3 = monty_mult(coord_z, z2); + + BigInt ax_z4 = monty_mult(ax, monty_sqr(z2)); + + BigInt b_z6 = monty_mult(b_r, monty_sqr(z3)); + + if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1)) + return false; + + return true; + } + +// swaps the states of *this and other, does not throw! +void PointGFp::swap(PointGFp& other) + { + curve.swap(other.curve); + coord_x.swap(other.coord_x); + coord_y.swap(other.coord_y); + coord_z.swap(other.coord_z); + ws.swap(other.ws); + } + +bool PointGFp::operator==(const PointGFp& other) const + { + if(get_curve() != other.get_curve()) + return false; + + // If this is zero, only equal if other is also zero + if(is_zero()) + return other.is_zero(); + + return (get_affine_x() == other.get_affine_x() && + get_affine_y() == other.get_affine_y()); + } + +// encoding and decoding +SecureVector EC2OSP(const PointGFp& point, byte format) + { + if(point.is_zero()) + return SecureVector(1); // single 0 byte + + const size_t p_bytes = point.get_curve().get_p().bytes(); + + BigInt x = point.get_affine_x(); + BigInt y = point.get_affine_y(); + + SecureVector bX = BigInt::encode_1363(x, p_bytes); + SecureVector bY = BigInt::encode_1363(y, p_bytes); + + if(format == PointGFp::UNCOMPRESSED) + { + SecureVector result; + result.push_back(0x04); + + result += bX; + result += bY; + + return result; + } + else if(format == PointGFp::COMPRESSED) + { + SecureVector result; + result.push_back(0x02 | static_cast(y.get_bit(0))); + + result += bX; + + return result; + } + else if(format == PointGFp::HYBRID) + { + SecureVector result; + result.push_back(0x06 | static_cast(y.get_bit(0))); + + result += bX; + result += bY; + + return result; + } + else + throw Invalid_Argument("illegal point encoding format specification"); + } + +namespace { + +BigInt decompress_point(bool yMod2, + const BigInt& x, + const CurveGFp& curve) + { + BigInt xpow3 = x * x * x; + + BigInt g = curve.get_a() * x; + g += xpow3; + g += curve.get_b(); + g = g % curve.get_p(); + + BigInt z = ressol(g, curve.get_p()); + + if(z < 0) + throw Illegal_Point("error during decompression"); + + if(z.get_bit(0) != yMod2) + z = curve.get_p() - z; + + return z; + } + +} + +PointGFp OS2ECP(const byte data[], size_t data_len, + const CurveGFp& curve) + { + if(data_len <= 1) + return PointGFp(curve); // return zero + + const byte pc = data[0]; + + BigInt x, y; + + if(pc == 2 || pc == 3) + { + //compressed form + x = BigInt::decode(&data[1], data_len - 1); + + const bool y_mod_2 = ((pc & 0x01) == 1); + y = decompress_point(y_mod_2, x, curve); + } + else if(pc == 4) + { + const size_t l = (data_len - 1) / 2; + + // uncompressed form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + } + else if(pc == 6 || pc == 7) + { + const size_t l = (data_len - 1) / 2; + + // hybrid form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + + const bool y_mod_2 = ((pc & 0x01) == 1); + + if(decompress_point(y_mod_2, x, curve) != y) + throw Illegal_Point("OS2ECP: Decoding error in hybrid format"); + } + else + throw Invalid_Argument("OS2ECP: Unknown format type"); + + PointGFp result(curve, x, y); + + if(!result.on_the_curve()) + throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); + + return result; + } + +} +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Two Operand Addition, No Carry +*/ +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) + { + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add2(x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Three Operand Addition, No Carry +*/ +word bigint_add3_nc(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) + { return bigint_add3_nc(z, y, y_size, x, x_size); } + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add3(z + i, x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Two Operand Addition +*/ +void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) + { + if(bigint_add2_nc(x, x_size, y, y_size)) + x[x_size] += 1; + } + +/* +* Three Operand Addition +*/ +void bigint_add3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + z[(x_size > y_size ? x_size : y_size)] += + bigint_add3_nc(z, x, x_size, y, y_size); + } + +/* +* Two Operand Subtraction +*/ +word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Subtraction x = y - x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2_rev(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(y[i], x[i], &borrow); + + if(borrow) + throw Internal_Error("bigint_sub2_rev: x >= y"); + } + +/* +* Three Operand Subtraction +*/ +word bigint_sub3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub3(z + i, x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul2(x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + x[i] = word_madd2(x[i], y, &carry); + + x[x_size] = carry; + } + +/* +* Three Operand Linear Multiply +*/ +void bigint_linmul3(word z[], const word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul3(z + i, x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + z[i] = word_madd2(x[i], y, &carry); + + z[x_size] = carry; + } + +} + +} +/* +* Comba Multiplication and Squaring +* (C) 1999-2007,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Comba 4x4 Squaring +*/ +void bigint_comba_sqr4(word z[8], const word x[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 4x4 Multiplication +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 6x6 Squaring +*/ +void bigint_comba_sqr6(word z[12], const word x[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 6x6 Multiplication +*/ +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 8x8 Squaring +*/ +void bigint_comba_sqr8(word z[16], const word x[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 8x8 Multiplication +*/ +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 16x16 Squaring +*/ +void bigint_comba_sqr16(word z[32], const word x[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd(&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd(&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd(&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd(&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd(&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 16x16 Multiplication +*/ +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + z[30] = w0; + z[31] = w1; + } + +} + +} +/* +* Karatsuba Multiplication/Squaring +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Karatsuba Multiplication Operation +*/ +void karatsuba_mul(word z[], const word x[], const word y[], size_t N, + word workspace[]) + { + if(N < BOTAN_KARAT_MUL_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_mul6(z, x, y); + else if(N == 8) + return bigint_comba_mul8(z, x, y); + else if(N == 16) + return bigint_comba_mul16(z, x, y); + else + return bigint_simple_mul(z, x, N, y, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + const word* y0 = y; + const word* y1 = y + N2; + word* z0 = z; + word* z1 = z + N; + + const s32bit cmp0 = bigint_cmp(x0, N2, x1, N2); + const s32bit cmp1 = bigint_cmp(y1, N2, y0, N2); + + clear_mem(workspace, 2*N); + + if(cmp0 && cmp1) + { + if(cmp0 > 0) + bigint_sub3(z0, x0, N2, x1, N2); + else + bigint_sub3(z0, x1, N2, x0, N2); + + if(cmp1 > 0) + bigint_sub3(z1, y1, N2, y0, N2); + else + bigint_sub3(z1, y0, N2, y1, N2); + + karatsuba_mul(workspace, z0, z1, N2, workspace+N); + } + + karatsuba_mul(z0, x0, y0, N2, workspace+N); + karatsuba_mul(z1, x1, y1, N2, workspace+N); + + const size_t blocks_of_8 = N - (N % 8); + + word ws_carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + ws_carry = word8_add3(workspace + N + j, z0 + j, z1 + j, ws_carry); + + for(size_t j = blocks_of_8; j != N; ++j) + workspace[N + j] = word_add(z0[j], z1[j], &ws_carry); + + word z_carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + z_carry = word8_add2(z + N2 + j, workspace + N + j, z_carry); + + for(size_t j = blocks_of_8; j != N; ++j) + z[N2 + j] = word_add(z[N2 + j], workspace[N + j], &z_carry); + + z[N + N2] = word_add(z[N + N2], ws_carry, &z_carry); + + if(z_carry) + for(size_t j = 1; j != N2; ++j) + if(++z[N + N2 + j]) + break; + + if((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0)) + bigint_add2(z + N2, 2*N-N2, workspace, N); + else + bigint_sub2(z + N2, 2*N-N2, workspace, N); + } + +/* +* Karatsuba Squaring Operation +*/ +void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[]) + { + if(N < BOTAN_KARAT_SQR_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_sqr6(z, x); + else if(N == 8) + return bigint_comba_sqr8(z, x); + else if(N == 16) + return bigint_comba_sqr16(z, x); + else + return bigint_simple_sqr(z, x, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + word* z0 = z; + word* z1 = z + N; + + const s32bit cmp = bigint_cmp(x0, N2, x1, N2); + + clear_mem(workspace, 2*N); + + if(cmp) + { + if(cmp > 0) + bigint_sub3(z0, x0, N2, x1, N2); + else + bigint_sub3(z0, x1, N2, x0, N2); + + karatsuba_sqr(workspace, z0, N2, workspace+N); + } + + karatsuba_sqr(z0, x0, N2, workspace+N); + karatsuba_sqr(z1, x1, N2, workspace+N); + + const size_t blocks_of_8 = N - (N % 8); + + word ws_carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + ws_carry = word8_add3(workspace + N + j, z0 + j, z1 + j, ws_carry); + + for(size_t j = blocks_of_8; j != N; ++j) + workspace[N + j] = word_add(z0[j], z1[j], &ws_carry); + + word z_carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + z_carry = word8_add2(z + N2 + j, workspace + N + j, z_carry); + + for(size_t j = blocks_of_8; j != N; ++j) + z[N2 + j] = word_add(z[N2 + j], workspace[N + j], &z_carry); + + z[N + N2] = word_add(z[N + N2], ws_carry, &z_carry); + + if(z_carry) + for(size_t j = 1; j != N2; ++j) + if(++z[N + N2 + j]) + break; + + /* + * This is only actually required if cmp is != 0, however + * if cmp==0 then workspace[0:N] == 0 and avoiding the jump + * hides a timing channel. + */ + bigint_sub2(z + N2, 2*N-N2, workspace, N); + } + +/* +* Pick a good size for the Karatsuba multiply +*/ +size_t karatsuba_size(size_t z_size, + size_t x_size, size_t x_sw, + size_t y_size, size_t y_sw) + { + if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) + return 0; + + if(((x_size == x_sw) && (x_size % 2)) || + ((y_size == y_sw) && (y_size % 2))) + return 0; + + const size_t start = (x_sw > y_sw) ? x_sw : y_sw; + const size_t end = (x_size < y_size) ? x_size : y_size; + + if(start == end) + { + if(start % 2) + return 0; + return start; + } + + for(size_t j = start; j <= end; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) + { + if(j % 4 == 2 && + (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + } + + return 0; + } + +/* +* Pick a good size for the Karatsuba squaring +*/ +size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw) + { + if(x_sw == x_size) + { + if(x_sw % 2) + return 0; + return x_sw; + } + + for(size_t j = x_sw; j <= x_size; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + + return 0; + } + +} + +/* +* Multiplication Algorithm Dispatcher +*/ +void bigint_mul(word z[], size_t z_size, word workspace[], + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw) + { + if(x_sw == 1) + { + bigint_linmul3(z, y, y_sw, x[0]); + } + else if(y_sw == 1) + { + bigint_linmul3(z, x, x_sw, y[0]); + } + else if(x_sw <= 4 && x_size >= 4 && + y_sw <= 4 && y_size >= 4 && z_size >= 8) + { + bigint_comba_mul4(z, x, y); + } + else if(x_sw <= 6 && x_size >= 6 && + y_sw <= 6 && y_size >= 6 && z_size >= 12) + { + bigint_comba_mul6(z, x, y); + } + else if(x_sw <= 8 && x_size >= 8 && + y_sw <= 8 && y_size >= 8 && z_size >= 16) + { + bigint_comba_mul8(z, x, y); + } + else if(x_sw <= 16 && x_size >= 16 && + y_sw <= 16 && y_size >= 16 && z_size >= 32) + { + bigint_comba_mul16(z, x, y); + } + else if(x_sw < BOTAN_KARAT_MUL_THRESHOLD || + y_sw < BOTAN_KARAT_MUL_THRESHOLD || + !workspace) + { + bigint_simple_mul(z, x, x_sw, y, y_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); + + if(N) + { + clear_mem(workspace, 2*N); + karatsuba_mul(z, x, y, N, workspace); + } + else + bigint_simple_mul(z, x, x_sw, y, y_sw); + } + } + +/* +* Squaring Algorithm Dispatcher +*/ +void bigint_sqr(word z[], size_t z_size, word workspace[], + const word x[], size_t x_size, size_t x_sw) + { + if(x_sw == 1) + { + bigint_linmul3(z, x, x_sw, x[0]); + } + else if(x_sw <= 4 && x_size >= 4 && z_size >= 8) + { + bigint_comba_sqr4(z, x); + } + else if(x_sw <= 6 && x_size >= 6 && z_size >= 12) + { + bigint_comba_sqr6(z, x); + } + else if(x_sw <= 8 && x_size >= 8 && z_size >= 16) + { + bigint_comba_sqr8(z, x); + } + else if(x_sw <= 16 && x_size >= 16 && z_size >= 32) + { + bigint_comba_sqr16(z, x); + } + else if(x_size < BOTAN_KARAT_SQR_THRESHOLD || !workspace) + { + bigint_simple_sqr(z, x, x_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw); + + if(N) + { + clear_mem(workspace, 2*N); + karatsuba_sqr(z, x, N, workspace); + } + else + bigint_simple_sqr(z, x, x_sw); + } + } + +} +/* +* MP Misc Functions +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Core Division Operation +*/ +size_t bigint_divcore(word q, word y2, word y1, + word x3, word x2, word x1) + { + // Compute (y2,y1) * q + + word y3 = 0; + y1 = word_madd2(q, y1, &y3); + y2 = word_madd2(q, y2, &y3); + + // Return (y3,y2,y1) >? (x3,x2,x1) + + if(y3 > x3) return 1; + if(y3 < x3) return 0; + if(y2 > x2) return 1; + if(y2 < x2) return 0; + if(y1 > x1) return 1; + if(y1 < x1) return 0; + return 0; + } + +/* +* Compare two MP integers +*/ +s32bit bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); } + + while(x_size > y_size) + { + if(x[x_size-1]) + return 1; + x_size--; + } + + for(size_t j = x_size; j > 0; --j) + { + if(x[j-1] > y[j-1]) + return 1; + if(x[j-1] < y[j-1]) + return -1; + } + + return 0; + } + +/* +* Do a 2-word/1-word Division +*/ +word bigint_divop(word n1, word n0, word d) + { + word high = n1 % d, quotient = 0; + + for(size_t j = 0; j != MP_WORD_BITS; ++j) + { + word high_top_bit = (high & MP_WORD_TOP_BIT); + + high <<= 1; + high |= (n0 >> (MP_WORD_BITS-1-j)) & 1; + quotient <<= 1; + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= 1; + } + } + + return quotient; + } + +/* +* Do a 2-word/1-word Modulo +*/ +word bigint_modop(word n1, word n0, word d) + { + word z = bigint_divop(n1, n0, d); + word dummy = 0; + z = word_madd2(z, d, &dummy); + return (n0-z); + } + +} + +} +/* +* Montgomery Reduction +* (C) 1999-2011 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Montgomery Reduction Algorithm +*/ +void bigint_monty_redc(word z[], size_t z_size, + const word p[], size_t p_size, + word p_dash, word ws[]) + { + const size_t blocks_of_8 = p_size - (p_size % 8); + + for(size_t i = 0; i != p_size; ++i) + { + word* z_i = z + i; + + const word y = z_i[0] * p_dash; + + /* + bigint_linmul3(ws, p, p_size, y); + bigint_add2(z_i, z_size - i, ws, p_size+1); + */ + + word carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + carry = word8_madd3(z_i + j, p + j, y, carry); + + for(size_t j = blocks_of_8; j != p_size; ++j) + z_i[j] = word_madd3(p[j], y, z_i[j], &carry); + + word z_sum = z_i[p_size] + carry; + carry = (z_sum < z_i[p_size]); + z_i[p_size] = z_sum; + + for(size_t j = p_size + 1; carry && j != z_size - i; ++j) + { + ++z_i[j]; + carry = !z_i[j]; + } + } + + word borrow = 0; + for(size_t i = 0; i != p_size; ++i) + ws[i] = word_sub(z[p_size + i], p[i], &borrow); + + ws[p_size] = word_sub(z[p_size+p_size], 0, &borrow); + + copy_mem(ws + p_size + 1, z + p_size, p_size + 1); + + copy_mem(z, ws + borrow*(p_size+1), p_size + 1); + clear_mem(z + p_size + 1, z_size - p_size - 1); + } + +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_mul(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw, + &y[0], y_size, y_sw); + + bigint_monty_redc(&z[0], z_size, + &p[0], p_size, p_dash, + &ws[0]); + } + +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_sqr(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw); + + bigint_monty_redc(&z[0], z_size, + &p[0], p_size, p_dash, + &ws[0]); + } + +} + +} +/* +* Simple O(N^2) Multiplication and Squaring +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Simple O(N^2) Multiplication +*/ +void bigint_simple_mul(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, x_size + y_size); + + for(size_t i = 0; i != y_size; ++i) + { + const word y_i = y[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, y_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +/* +* Simple O(N^2) Squaring +* +* This is exactly the same algorithm as bigint_simple_mul, however +* because C/C++ compilers suck at alias analysis it is good to have +* the version where the compiler knows that x == y +* +* There is an O(n^1.5) squaring algorithm specified in Handbook of +* Applied Cryptography, chapter 14 +* +*/ +void bigint_simple_sqr(word z[], const word x[], size_t x_size) + { + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, 2*x_size); + + for(size_t i = 0; i != x_size; ++i) + { + const word x_i = x[i]; + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, x_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +} + +} +/* +* MP Shift Algorithms +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +extern "C" { + +/* +* Single Operand Left Shift +*/ +void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(word_shift) + { + for(size_t j = 1; j != x_size + 1; ++j) + x[(x_size - j) + word_shift] = x[x_size - j]; + clear_mem(x, word_shift); + } + + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word temp = x[j]; + x[j] = (temp << bit_shift) | carry; + carry = (temp >> (MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Single Operand Right Shift +*/ +void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) + { + clear_mem(x, x_size); + return; + } + + if(word_shift) + { + copy_mem(x, x + word_shift, x_size - word_shift); + clear_mem(x + x_size - word_shift, word_shift); + } + + if(bit_shift) + { + word carry = 0; + + size_t top = x_size - word_shift; + + while(top >= 4) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-2]; + x[top-2] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-3]; + x[top-3] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + w = x[top-4]; + x[top-4] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + top -= 4; + } + + while(top) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + + top--; + } + } + } + +/* +* Two Operand Left Shift +*/ +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + for(size_t j = 0; j != x_size; ++j) + y[j + word_shift] = x[j]; + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word w = y[j]; + y[j] = (w << bit_shift) | carry; + carry = (w >> (MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Two Operand Right Shift +*/ +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) return; + + for(size_t j = 0; j != x_size - word_shift; ++j) + y[j] = x[j + word_shift]; + if(bit_shift) + { + word carry = 0; + for(size_t j = x_size - word_shift; j > 0; --j) + { + word w = y[j-1]; + y[j-1] = (w >> bit_shift) | carry; + carry = (w << (MP_WORD_BITS - bit_shift)); + } + } + } + +} + +} +/* +* DSA Parameter Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +* Check if this size is allowed by FIPS 186-3 +*/ +bool fips186_3_valid_size(size_t pbits, size_t qbits) + { + if(qbits == 160) + return (pbits == 512 || pbits == 768 || pbits == 1024); + + if(qbits == 224) + return (pbits == 2048); + + if(qbits == 256) + return (pbits == 2048 || pbits == 3072); + + return false; + } + +} + +/* +* Attempt DSA prime generation with given seed +*/ +bool generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits, + const MemoryRegion& seed_c) + { + if(!fips186_3_valid_size(pbits, qbits)) + throw Invalid_Argument( + "FIPS 186-3 does not allow DSA domain parameters of " + + to_string(pbits) + "/" + to_string(qbits) + " bits long"); + + if(seed_c.size() * 8 < qbits) + throw Invalid_Argument( + "Generating a DSA parameter set with a " + to_string(qbits) + + "long q requires a seed at least as many bits long"); + + std::unique_ptr hash( + af.make_hash_function("SHA-" + to_string(qbits))); + + const size_t HASH_SIZE = hash->output_length(); + + class Seed + { + public: + Seed(const MemoryRegion& s) : seed(s) {} + + operator MemoryRegion& () { return seed; } + + Seed& operator++() + { + for(size_t j = seed.size(); j > 0; --j) + if(++seed[j-1]) + break; + return (*this); + } + private: + SecureVector seed; + }; + + Seed seed(seed_c); + + q.binary_decode(hash->process(seed)); + q.set_bit(qbits-1); + q.set_bit(0); + + if(!check_prime(q, rng)) + return false; + + const size_t n = (pbits-1) / (HASH_SIZE * 8), + b = (pbits-1) % (HASH_SIZE * 8); + + BigInt X; + SecureVector V(HASH_SIZE * (n+1)); + + for(size_t j = 0; j != 4096; ++j) + { + for(size_t k = 0; k <= n; ++k) + { + ++seed; + hash->update(seed); + hash->final(&V[HASH_SIZE * (n-k)]); + } + + X.binary_decode(&V[HASH_SIZE - 1 - b/8], + V.size() - (HASH_SIZE - 1 - b/8)); + X.set_bit(pbits-1); + + p = X - (X % (2*q) - 1); + + if(p.bits() == pbits && check_prime(p, rng)) + return true; + } + return false; + } + +/* +* Generate DSA Primes +*/ +SecureVector generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits) + { + while(true) + { + SecureVector seed = rng.random_vec(qbits / 8); + + if(generate_dsa_primes(rng, af, p, q, pbits, qbits, seed)) + return seed; + } + } + +} +/* +* Jacobi Function +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Calculate the Jacobi symbol +*/ +s32bit jacobi(const BigInt& a, const BigInt& n) + { + if(a.is_negative()) + throw Invalid_Argument("jacobi: first argument must be non-negative"); + if(n.is_even() || n < 2) + throw Invalid_Argument("jacobi: second argument must be odd and > 1"); + + BigInt x = a, y = n; + s32bit J = 1; + + while(y > 1) + { + x %= y; + if(x > y / 2) + { + x = y - x; + if(y % 4 == 3) + J = -J; + } + if(x.is_zero()) + return 0; + + size_t shifts = low_zero_bits(x); + x >>= shifts; + if(shifts % 2) + { + word y_mod_8 = y % 8; + if(y_mod_8 == 3 || y_mod_8 == 5) + J = -J; + } + + if(x % 4 == 3 && y % 4 == 3) + J = -J; + std::swap(x, y); + } + return J; + } + +} +/* +* Prime Generation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Generate a random prime +*/ +BigInt random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime, + size_t equiv, size_t modulo) + { + if(bits <= 1) + throw Invalid_Argument("random_prime: Can't make a prime of " + + to_string(bits) + " bits"); + else if(bits == 2) + return ((rng.next_byte() % 2) ? 2 : 3); + else if(bits == 3) + return ((rng.next_byte() % 2) ? 5 : 7); + else if(bits == 4) + return ((rng.next_byte() % 2) ? 11 : 13); + + if(coprime <= 0) + throw Invalid_Argument("random_prime: coprime must be > 0"); + if(modulo % 2 == 1 || modulo == 0) + throw Invalid_Argument("random_prime: Invalid modulo value"); + if(equiv >= modulo || equiv % 2 == 0) + throw Invalid_Argument("random_prime: equiv must be < modulo, and odd"); + + while(true) + { + BigInt p(rng, bits); + + // Force lowest and two top bits on + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + if(p % modulo != equiv) + p += (modulo - p % modulo) + equiv; + + const size_t sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE); + SecureVector sieve(sieve_size); + + for(size_t j = 0; j != sieve.size(); ++j) + sieve[j] = p % PRIMES[j]; + + size_t counter = 0; + while(true) + { + if(counter == 4096 || p.bits() > bits) + break; + + bool passes_sieve = true; + ++counter; + p += modulo; + + if(p.bits() > bits) + break; + + for(size_t j = 0; j != sieve.size(); ++j) + { + sieve[j] = (sieve[j] + modulo) % PRIMES[j]; + if(sieve[j] == 0) + passes_sieve = false; + } + + if(!passes_sieve || gcd(p - 1, coprime) != 1) + continue; + if(check_prime(p, rng)) + return p; + } + } + } + +/* +* Generate a random safe prime +*/ +BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) + { + if(bits <= 64) + throw Invalid_Argument("random_safe_prime: Can't make a prime of " + + to_string(bits) + " bits"); + + BigInt p; + do + p = (random_prime(rng, bits - 1) << 1) + 1; + while(!check_prime(p, rng)); + return p; + } + +} +/* +* Fused and Important MP Algorithms +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Square a BigInt +*/ +BigInt square(const BigInt& x) + { + const size_t x_sw = x.sig_words(); + + BigInt z(BigInt::Positive, round_up(2*x_sw, 16)); + SecureVector workspace(z.size()); + + bigint_sqr(z.get_reg(), z.size(), workspace, + x.data(), x.size(), x_sw); + return z; + } + +/* +* Multiply-Add Operation +*/ +BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative() || c.is_zero()) + throw Invalid_Argument("mul_add: Third argument must be > 0"); + + BigInt::Sign sign = BigInt::Positive; + if(a.sign() != b.sign()) + sign = BigInt::Negative; + + const size_t a_sw = a.sig_words(); + const size_t b_sw = b.sig_words(); + const size_t c_sw = c.sig_words(); + + BigInt r(sign, std::max(a.size() + b.size(), c_sw) + 1); + SecureVector workspace(r.size()); + + bigint_mul(r.get_reg(), r.size(), workspace, + a.data(), a.size(), a_sw, + b.data(), b.size(), b_sw); + const size_t r_size = std::max(r.sig_words(), c_sw); + bigint_add2(r.get_reg(), r_size, c.data(), c_sw); + return r; + } + +/* +* Subtract-Multiply Operation +*/ +BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(a.is_negative() || b.is_negative()) + throw Invalid_Argument("sub_mul: First two arguments must be >= 0"); + + BigInt r = a; + r -= b; + r *= c; + return r; + } + +} +/* +* Number Theory Functions +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* Miller-Rabin Primality Tester +*/ +class MillerRabin_Test + { + public: + bool is_witness(const BigInt& nonce); + MillerRabin_Test(const BigInt& num); + private: + BigInt n, r, n_minus_1; + size_t s; + Fixed_Exponent_Power_Mod pow_mod; + Modular_Reducer reducer; + }; + +/* +* Miller-Rabin Test, as described in Handbook of Applied Cryptography +* section 4.24 +*/ +bool MillerRabin_Test::is_witness(const BigInt& a) + { + if(a < 2 || a >= n_minus_1) + throw Invalid_Argument("Bad size for nonce in Miller-Rabin test"); + + BigInt y = pow_mod(a); + if(y == 1 || y == n_minus_1) + return false; + + for(size_t i = 1; i != s; ++i) + { + y = reducer.square(y); + + if(y == 1) // found a non-trivial square root + return true; + + if(y == n_minus_1) // -1, trivial square root, so give up + return false; + } + + if(y != n_minus_1) // fails Fermat test + return true; + + return false; + } + +/* +* Miller-Rabin Constructor +*/ +MillerRabin_Test::MillerRabin_Test(const BigInt& num) + { + if(num.is_even() || num < 3) + throw Invalid_Argument("MillerRabin_Test: Invalid number for testing"); + + n = num; + n_minus_1 = n - 1; + s = low_zero_bits(n_minus_1); + r = n_minus_1 >> s; + + pow_mod = Fixed_Exponent_Power_Mod(r, n); + reducer = Modular_Reducer(n); + } + +/* +* Miller-Rabin Iterations +*/ +size_t miller_rabin_test_iterations(size_t bits, size_t level) + { + struct mapping { size_t bits; size_t verify_iter; size_t check_iter; }; + + static const mapping tests[] = { + { 50, 55, 25 }, + { 100, 38, 22 }, + { 160, 32, 18 }, + { 163, 31, 17 }, + { 168, 30, 16 }, + { 177, 29, 16 }, + { 181, 28, 15 }, + { 185, 27, 15 }, + { 190, 26, 15 }, + { 195, 25, 14 }, + { 201, 24, 14 }, + { 208, 23, 14 }, + { 215, 22, 13 }, + { 222, 21, 13 }, + { 231, 20, 13 }, + { 241, 19, 12 }, + { 252, 18, 12 }, + { 264, 17, 12 }, + { 278, 16, 11 }, + { 294, 15, 10 }, + { 313, 14, 9 }, + { 334, 13, 8 }, + { 360, 12, 8 }, + { 392, 11, 7 }, + { 430, 10, 7 }, + { 479, 9, 6 }, + { 542, 8, 6 }, + { 626, 7, 5 }, + { 746, 6, 4 }, + { 926, 5, 3 }, + { 1232, 4, 2 }, + { 1853, 3, 2 }, + { 0, 0, 0 } + }; + + for(size_t i = 0; tests[i].bits; ++i) + { + if(bits <= tests[i].bits) + { + if(level >= 2) + return tests[i].verify_iter; + else if(level == 1) + return tests[i].check_iter; + else if(level == 0) + return std::max(tests[i].check_iter / 4, 1); + } + } + + return level > 0 ? 2 : 1; // for large inputs + } + +} + +/* +* Return the number of 0 bits at the end of n +*/ +size_t low_zero_bits(const BigInt& n) + { + size_t low_zero = 0; + + if(n.is_positive() && n.is_nonzero()) + { + for(size_t i = 0; i != n.size(); ++i) + { + word x = n[i]; + + if(x) + { + low_zero += ctz(x); + break; + } + else + low_zero += BOTAN_MP_WORD_BITS; + } + } + + return low_zero; + } + +/* +* Calculate the GCD +*/ +BigInt gcd(const BigInt& a, const BigInt& b) + { + if(a.is_zero() || b.is_zero()) return 0; + if(a == 1 || b == 1) return 1; + + BigInt x = a, y = b; + x.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + size_t shift = std::min(low_zero_bits(x), low_zero_bits(y)); + + x >>= shift; + y >>= shift; + + while(x.is_nonzero()) + { + x >>= low_zero_bits(x); + y >>= low_zero_bits(y); + if(x >= y) { x -= y; x >>= 1; } + else { y -= x; y >>= 1; } + } + + return (y << shift); + } + +/* +* Calculate the LCM +*/ +BigInt lcm(const BigInt& a, const BigInt& b) + { + return ((a * b) / gcd(a, b)); + } + +/* +* Find the Modular Inverse +*/ +BigInt inverse_mod(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative() || n.is_negative()) + throw Invalid_Argument("inverse_mod: arguments must be non-negative"); + + if(n.is_zero() || (n.is_even() && mod.is_even())) + return 0; + + BigInt x = mod, y = n, u = mod, v = n; + BigInt A = 1, B = 0, C = 0, D = 1; + + while(u.is_nonzero()) + { + size_t zero_bits = low_zero_bits(u); + u >>= zero_bits; + for(size_t i = 0; i != zero_bits; ++i) + { + if(A.is_odd() || B.is_odd()) + { A += y; B -= x; } + A >>= 1; B >>= 1; + } + + zero_bits = low_zero_bits(v); + v >>= zero_bits; + for(size_t i = 0; i != zero_bits; ++i) + { + if(C.is_odd() || D.is_odd()) + { C += y; D -= x; } + C >>= 1; D >>= 1; + } + + if(u >= v) { u -= v; A -= C; B -= D; } + else { v -= u; C -= A; D -= B; } + } + + if(v != 1) + return 0; + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +/* +* Modular Exponentiation +*/ +BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) + { + Power_Mod pow_mod(mod); + pow_mod.set_base(base); + pow_mod.set_exponent(exp); + return pow_mod.execute(); + } + +/* +* Test for primaility using Miller-Rabin +*/ +bool primality_test(const BigInt& n, + RandomNumberGenerator& rng, + size_t level) + { + const size_t PREF_NONCE_BITS = 64; + + if(n == 2) + return true; + if(n <= 1 || n.is_even()) + return false; + + // Fast path testing for small numbers (<= 65521) + if(n <= PRIMES[PRIME_TABLE_SIZE-1]) + { + const word num = n.word_at(0); + + for(size_t i = 0; PRIMES[i]; ++i) + { + if(num == PRIMES[i]) + return true; + if(num < PRIMES[i]) + return false; + } + + return false; + } + + if(level > 2) + level = 2; + + const size_t NONCE_BITS = std::min(n.bits() - 2, PREF_NONCE_BITS); + + MillerRabin_Test mr(n); + + const size_t tests = miller_rabin_test_iterations(n.bits(), level); + + BigInt nonce; + for(size_t i = 0; i != tests; ++i) + { + while(nonce < 2 || nonce >= (n-1)) + nonce.randomize(rng, NONCE_BITS); + + if(mr.is_witness(nonce)) + return false; + } + return true; + } + +} +/* +* Modular Exponentiation Proxy +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Power_Mod Constructor +*/ +Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints) + { + core = 0; + set_modulus(n, hints); + } + +/* +* Power_Mod Copy Constructor +*/ +Power_Mod::Power_Mod(const Power_Mod& other) + { + Q_UNUSED(hints); + core = 0; + if(other.core) + core = other.core->copy(); + } + +/* +* Power_Mod Assignment Operator +*/ +Power_Mod& Power_Mod::operator=(const Power_Mod& other) + { + delete core; + core = 0; + if(other.core) + core = other.core->copy(); + return (*this); + } + +/* +* Power_Mod Destructor +*/ +Power_Mod::~Power_Mod() + { + delete core; + } + +/* +* Set the modulus +*/ +void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints) const + { + delete core; + core = 0; + + if(n != 0) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + core = engine->mod_exp(n, hints); + + if(core) + break; + } + + if(!core) + throw Lookup_Error("Power_Mod: Unable to find a working engine"); + } + } + +/* +* Set the base +*/ +void Power_Mod::set_base(const BigInt& b) const + { + if(b.is_zero() || b.is_negative()) + throw Invalid_Argument("Power_Mod::set_base: arg must be > 0"); + + if(!core) + throw Internal_Error("Power_Mod::set_base: core was NULL"); + core->set_base(b); + } + +/* +* Set the exponent +*/ +void Power_Mod::set_exponent(const BigInt& e) const + { + if(e.is_negative()) + throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0"); + + if(!core) + throw Internal_Error("Power_Mod::set_exponent: core was NULL"); + core->set_exponent(e); + } + +/* +* Compute the result +*/ +BigInt Power_Mod::execute() const + { + if(!core) + throw Internal_Error("Power_Mod::execute: core was NULL"); + return core->execute(); + } + +/* +* Try to choose a good window size +*/ +size_t Power_Mod::window_bits(size_t exp_bits, size_t, + Power_Mod::Usage_Hints hints) + { + static const size_t wsize[][2] = { + { 1434, 7 }, + { 539, 6 }, + { 197, 4 }, + { 70, 3 }, + { 25, 2 }, + { 0, 0 } + }; + + size_t window_bits = 1; + + if(exp_bits) + { + for(size_t j = 0; wsize[j][0]; ++j) + { + if(exp_bits >= wsize[j][0]) + { + window_bits += wsize[j][1]; + break; + } + } + } + + if(hints & Power_Mod::BASE_IS_FIXED) + window_bits += 2; + if(hints & Power_Mod::EXP_IS_LARGE) + ++window_bits; + + return window_bits; + } + +namespace { + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n) + { + if(b == 2) + return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 | + Power_Mod::BASE_IS_SMALL); + + const size_t b_bits = b.bits(); + const size_t n_bits = n.bits(); + + if(b_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(b_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + + return Power_Mod::NO_HINTS; + } + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n) + { + const size_t e_bits = e.bits(); + const size_t n_bits = n.bits(); + + if(e_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(e_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + return Power_Mod::NO_HINTS; + } + +} + +/* +* Fixed_Exponent_Power_Mod Constructor +*/ +Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e, + const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n))) + { + set_exponent(e); + } + +/* +* Fixed_Base_Power_Mod Constructor +*/ +Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n))) + { + set_base(b); + } + +} +/* +* Fixed Window Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Set the exponent +*/ +void Fixed_Window_Exponentiator::set_exponent(const BigInt& e) + { + exp = e; + } + +/* +* Set the base +*/ +void Fixed_Window_Exponentiator::set_base(const BigInt& base) + { + window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); + + g.resize((1 << window_bits) - 1); + g[0] = base; + for(size_t j = 1; j != g.size(); ++j) + g[j] = reducer.multiply(g[j-1], g[0]); + } + +/* +* Compute the result +*/ +BigInt Fixed_Window_Exponentiator::execute() const + { + const size_t exp_nibbles = (exp.bits() + window_bits - 1) / window_bits; + + BigInt x = 1; + for(size_t j = exp_nibbles; j > 0; --j) + { + for(size_t k = 0; k != window_bits; ++k) + x = reducer.square(x); + + if(u32bit nibble = exp.get_substring(window_bits*(j-1), window_bits)) + x = reducer.multiply(x, g[nibble-1]); + } + return x; + } + +/* +* Fixed_Window_Exponentiator Constructor +*/ +Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n, + Power_Mod::Usage_Hints hints) + { + reducer = Modular_Reducer(n); + this->hints = hints; + window_bits = 0; + } + +} +/* +* Montgomery Exponentiation +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Set the exponent +*/ +void Montgomery_Exponentiator::set_exponent(const BigInt& exp) + { + this->exp = exp; + exp_bits = exp.bits(); + } + +/* +* Set the base +*/ +void Montgomery_Exponentiator::set_base(const BigInt& base) + { + window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); + + g.resize((1 << window_bits) - 1); + + SecureVector z(2 * (mod_words + 1)); + SecureVector workspace(z.size()); + + g[0] = (base >= modulus) ? (base % modulus) : base; + + bigint_monty_mul(&z[0], z.size(), + g[0].data(), g[0].size(), g[0].sig_words(), + R2.data(), R2.size(), R2.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + g[0].assign(&z[0], mod_words + 1); + + const BigInt& x = g[0]; + const size_t x_sig = x.sig_words(); + + for(size_t i = 1; i != g.size(); ++i) + { + const BigInt& y = g[i-1]; + const size_t y_sig = y.sig_words(); + + zeroise(z); + bigint_monty_mul(&z[0], z.size(), + x.data(), x.size(), x_sig, + y.data(), y.size(), y_sig, + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + g[i].assign(&z[0], mod_words + 1); + } + } + +/* +* Compute the result +*/ +BigInt Montgomery_Exponentiator::execute() const + { + const size_t exp_nibbles = (exp_bits + window_bits - 1) / window_bits; + + BigInt x = R_mod; + SecureVector z(2 * (mod_words + 1)); + SecureVector workspace(2 * (mod_words + 1)); + + for(size_t i = exp_nibbles; i > 0; --i) + { + for(size_t k = 0; k != window_bits; ++k) + { + zeroise(z); + + bigint_monty_sqr(&z[0], z.size(), + x.data(), x.size(), x.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + x.assign(&z[0], mod_words + 1); + } + + if(u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits)) + { + const BigInt& y = g[nibble-1]; + + zeroise(z); + bigint_monty_mul(&z[0], z.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + x.assign(&z[0], mod_words + 1); + } + } + + x.get_reg().resize(2*mod_words+1); + + bigint_monty_redc(&x[0], x.size(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + x.get_reg().resize(mod_words+1); + + return x; + } + +/* +* Montgomery_Exponentiator Constructor +*/ +Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, + Power_Mod::Usage_Hints hints) + { + // Montgomery reduction only works for positive odd moduli + if(!mod.is_positive() || mod.is_even()) + throw Invalid_Argument("Montgomery_Exponentiator: invalid modulus"); + + window_bits = 0; + this->hints = hints; + modulus = mod; + + mod_words = modulus.sig_words(); + + BigInt r(BigInt::Power2, mod_words * BOTAN_MP_WORD_BITS); + mod_prime = (((r * inverse_mod(r, mod)) - 1) / mod).word_at(0); + + R_mod = r % modulus; + + R2 = (R_mod * R_mod) % modulus; + } + +} +/* +* Small Primes Table +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const u16bit PRIMES[PRIME_TABLE_SIZE+1] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, + 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, + 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, + 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, + 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, + 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, + 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, + 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, + 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, + 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, + 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, + 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, + 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, + 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, + 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, + 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, + 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, + 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, + 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, + 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, + 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, + 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, + 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, + 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, + 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, + 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, + 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, + 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, + 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, + 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, + 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, + 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, + 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, + 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, + 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, + 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, + 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, + 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, + 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, + 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, + 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, + 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, + 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, + 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, + 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, + 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, + 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, + 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, + 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, + 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, + 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, + 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, + 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, + 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, + 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, + 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, + 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, + 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, + 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, + 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, + 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, + 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, + 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, + 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, + 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, + 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, + 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, + 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, + 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, + 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, + 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, + 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, + 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, + 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, + 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, + 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, +10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, +10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, +10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, +10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, +10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, +10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, +10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, +10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, +10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, +10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, +11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, +11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, +11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, +11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, +11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, +11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, +11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, +11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, +11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, +12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, +12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, +12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, +12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, +12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, +12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, +12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, +12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, +12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, +12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, +13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, +13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, +13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, +13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, +13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, +13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, +13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, +13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, +13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, +13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, +14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, +14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, +14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, +14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, +14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, +14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, +14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, +14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, +14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, +15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, +15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, +15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, +15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, +15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, +15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, +15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, +15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, +15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, +15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, +16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, +16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, +16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, +16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, +16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, +16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, +16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, +16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, +16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, +17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, +17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, +17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, +17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, +17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, +17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, +17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, +17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, +17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, +18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, +18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, +18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, +18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, +18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, +18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, +18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, +18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, +18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, +19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, +19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, +19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, +19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, +19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, +19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, +19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, +19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, +19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, +20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, +20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, +20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, +20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, +20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, +20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, +20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, +20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, +20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, +21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, +21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, +21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, +21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, +21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, +21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, +21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, +21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, +21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, +22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, +22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, +22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, +22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, +22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, +22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, +22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, +22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, +22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, +23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, +23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, +23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, +23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, +23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, +23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, +23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, +23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, +23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, +23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, +24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, +24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, +24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, +24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, +24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, +24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, +24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, +24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, +25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, +25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, +25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, +25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, +25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, +25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, +25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, +25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, +25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, +26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, +26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, +26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, +26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, +26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, +26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, +26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, +26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, +26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, +26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, +27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, +27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, +27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, +27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, +27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, +27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, +27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, +27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, +28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, +28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, +28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, +28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, +28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, +28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, +28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, +28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, +28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, +29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, +29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, +29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, +29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, +29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, +29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, +29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, +29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, +30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, +30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, +30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, +30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, +30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, +30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, +30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, +30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, +30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, +31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, +31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, +31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, +31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, +31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, +31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, +31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, +31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, +32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, +32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, +32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, +32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, +32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, +32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, +32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, +32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, +32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, +32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, +33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, +33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, +33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, +33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, +33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, +33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, +33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, +33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, +33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, +34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, +34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, +34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, +34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, +34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, +34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, +34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, +34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, +34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, +35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, +35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, +35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, +35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, +35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, +35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, +35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, +35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, +36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, +36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, +36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, +36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, +36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, +36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, +36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, +36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, +36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, +37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, +37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, +37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, +37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, +37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, +37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, +37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, +37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, +37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, +38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, +38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, +38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, +38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, +38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, +38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, +38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, +38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, +39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, +39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, +39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, +39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, +39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, +39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, +39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, +39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, +40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, +40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, +40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, +40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, +40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, +40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, +40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, +40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, +41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, +41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, +41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, +41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, +41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, +41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, +41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, +41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, +41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, +41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, +42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, +42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, +42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, +42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, +42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, +42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, +42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, +42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, +42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, +43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, +43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, +43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, +43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, +43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, +43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, +43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, +43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, +44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, +44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, +44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, +44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, +44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, +44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, +44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, +44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, +45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, +45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, +45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, +45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, +45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, +45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, +45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, +45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, +46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, +46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, +46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, +46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, +46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, +46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, +46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, +46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, +47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, +47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, +47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, +47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, +47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, +47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, +47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, +47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, +47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, +48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, +48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, +48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, +48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, +48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, +48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, +48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, +48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, +49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, +49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, +49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, +49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, +49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, +49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, +49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, +49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, +49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, +50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, +50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, +50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, +50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, +50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, +50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, +50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, +50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, +51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, +51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, +51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, +51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, +51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, +51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, +51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, +51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, +51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, +52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, +52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, +52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, +52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, +52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, +52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, +52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, +52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, +53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, +53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, +53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, +53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, +53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, +53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, +53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, +53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, +54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, +54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, +54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, +54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, +54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, +54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, +54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, +54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, +54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, +55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, +55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, +55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, +55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, +55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, +55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, +55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, +55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, +56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, +56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, +56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, +56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, +56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, +56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, +56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, +56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, +56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, +57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, +57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, +57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, +57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, +57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, +57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, +57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, +57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, +58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, +58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, +58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, +58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, +58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, +58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, +58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, +58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, +59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, +59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, +59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, +59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, +59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, +59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, +59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, +59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, +59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, +60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, +60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, +60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, +60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, +60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, +60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, +60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, +60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, +61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, +61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, +61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, +61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, +61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, +61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, +61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, +61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, +62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, +62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, +62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, +62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, +62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, +62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, +62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, +62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, +63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, +63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, +63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, +63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, +63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, +63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, +63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, +63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, +64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, +64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, +64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, +64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, +64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, +64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, +64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, +64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, +65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, +65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, +65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, +65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 }; + +} +/* +* Modular Reducer +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Modular_Reducer Constructor +*/ +Modular_Reducer::Modular_Reducer(const BigInt& mod) + { + if(mod <= 0) + throw Invalid_Argument("Modular_Reducer: modulus must be positive"); + + modulus = mod; + mod_words = modulus.sig_words(); + + modulus_2 = Botan::square(modulus); + + mu = BigInt(BigInt::Power2, 2 * MP_WORD_BITS * mod_words) / modulus; + } + +/* +* Barrett Reduction +*/ +BigInt Modular_Reducer::reduce(const BigInt& x) const + { + if(mod_words == 0) + throw Invalid_State("Modular_Reducer: Never initalized"); + + if(x.cmp(modulus, false) < 0) + { + if(x.is_negative()) + return x + modulus; // make positive + return x; + } + else if(x.cmp(modulus_2, false) < 0) + { + BigInt t1 = x; + t1.set_sign(BigInt::Positive); + t1 >>= (MP_WORD_BITS * (mod_words - 1)); + t1 *= mu; + + t1 >>= (MP_WORD_BITS * (mod_words + 1)); + t1 *= modulus; + + t1.mask_bits(MP_WORD_BITS * (mod_words + 1)); + + BigInt t2 = x; + t2.set_sign(BigInt::Positive); + t2.mask_bits(MP_WORD_BITS * (mod_words + 1)); + + t2 -= t1; + + if(t2.is_negative()) + { + BigInt b_to_k1(BigInt::Power2, MP_WORD_BITS * (mod_words + 1)); + t2 += b_to_k1; + } + + while(t2 >= modulus) + t2 -= modulus; + + if(x.is_positive()) + return t2; + else + return (modulus - t2); + } + else + { + // too big, fall back to normal division + return (x % modulus); + } + } + +} +/* +* Shanks-Tonnelli (RESSOL) +* (C) 2007-2008 Falko Strenzke, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Shanks-Tonnelli algorithm +*/ +BigInt ressol(const BigInt& a, const BigInt& p) + { + if(a < 0) + throw Invalid_Argument("ressol(): a to solve for must be positive"); + if(p <= 1) + throw Invalid_Argument("ressol(): prime must be > 1"); + + if(a == 0) + return 0; + if(p == 2) + return a; + + if(jacobi(a, p) != 1) // not a quadratic residue + return -BigInt(1); + + if(p % 4 == 3) + return power_mod(a, ((p+1) >> 2), p); + + size_t s = low_zero_bits(p - 1); + BigInt q = p >> s; + + q -= 1; + q >>= 1; + + Modular_Reducer mod_p(p); + + BigInt r = power_mod(a, q, p); + BigInt n = mod_p.multiply(a, mod_p.square(r)); + r = mod_p.multiply(r, a); + + if(n == 1) + return r; + + // find random non quadratic residue z + BigInt z = 2; + while(jacobi(z, p) == 1) // while z quadratic residue + ++z; + + BigInt c = power_mod(z, (q << 1) + 1, p); + + while(n > 1) + { + q = n; + + size_t i = 0; + while(q != 1) + { + q = mod_p.square(q); + ++i; + } + + if(s <= i) + return -BigInt(1); + + c = power_mod(c, BigInt(BigInt::Power2, s-i-1), p); + r = mod_p.multiply(r, c); + c = mod_p.square(c); + n = mod_p.multiply(n, c); + s = i; + } + + return r; + } + +} +/* +* No-Op Mutex Factory +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* No-Op Mutex Factory +*/ +Mutex* Noop_Mutex_Factory::make() + { + class Noop_Mutex : public Mutex + { + public: + class Mutex_State_Error : public Internal_Error + { + public: + Mutex_State_Error(const std::string& where) : + Internal_Error("Noop_Mutex::" + where + ": " + + "Mutex is already " + where + "ed") {} + }; + + void lock() + { + if(locked) + throw Mutex_State_Error("lock"); + locked = true; + } + + void unlock() + { + if(!locked) + throw Mutex_State_Error("unlock"); + locked = false; + } + + Noop_Mutex() { locked = false; } + private: + bool locked; + }; + + return new Noop_Mutex; + } + +} + +#ifdef Q_OS_WIN +/* +* Win32 Mutex +* (C) 2006 Luca Piccarreta +* 2006-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Win32 Mutex Factory +*/ +Mutex* Win32_Mutex_Factory::make() + { + class Win32_Mutex : public Mutex + { + public: + void lock() { EnterCriticalSection(&mutex); } + void unlock() { LeaveCriticalSection(&mutex); } + + Win32_Mutex() { InitializeCriticalSection(&mutex); } + ~Win32_Mutex() { DeleteCriticalSection(&mutex); } + private: + CRITICAL_SECTION mutex; + }; + + return new Win32_Mutex(); + } + +} +#endif + +#ifdef Q_OS_UNIX +/* +* Pthread Mutex +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199506 +#endif + +#include + +namespace Botan { + +/* +* Pthread Mutex Factory +*/ +Mutex* Pthread_Mutex_Factory::make() + { + + class Pthread_Mutex : public Mutex + { + public: + void lock() + { + if(pthread_mutex_lock(&mutex) != 0) + throw Invalid_State("Pthread_Mutex::lock: Error occured"); + } + + void unlock() + { + if(pthread_mutex_unlock(&mutex) != 0) + throw Invalid_State("Pthread_Mutex::unlock: Error occured"); + } + + Pthread_Mutex() + { + if(pthread_mutex_init(&mutex, 0) != 0) + throw Invalid_State("Pthread_Mutex: initialization failed"); + } + + ~Pthread_Mutex() + { + if(pthread_mutex_destroy(&mutex) != 0) + throw Invalid_State("~Pthread_Mutex: mutex is still locked"); + } + private: + pthread_mutex_t mutex; + }; + + return new Pthread_Mutex(); + } + +} +#endif + +/* +* Bcrypt Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +std::string bcrypt_base64_encode(const byte input[], size_t length) + { + // Bcrypt uses a non-standard base64 alphabet + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, + 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + std::string b64 = base64_encode(input, length); + + while(b64.size() && b64[b64.size()-1] == '=') + b64 = b64.substr(0, b64.size() - 1); + + for(size_t i = 0; i != b64.size(); ++i) + b64[i] = OPENBSD_BASE64_SUB[static_cast(b64[i])]; + + return b64; + } + +MemoryVector bcrypt_base64_decode(std::string input) + { + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + for(size_t i = 0; i != input.size(); ++i) + input[i] = OPENBSD_BASE64_SUB[static_cast(input[i])]; + + return base64_decode(input); + } + +std::string make_bcrypt(const std::string& pass, + const MemoryRegion& salt, + u16bit work_factor) + { + const byte magic[24] = { + 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, + 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 + }; + + MemoryVector ctext(magic, 24); + + Blowfish blowfish; + + // Include the trailing NULL byte + blowfish.eks_key_schedule(reinterpret_cast(pass.c_str()), + pass.length() + 1, + salt, + work_factor); + + for(size_t i = 0; i != 64; ++i) + blowfish.encrypt_n(&ctext[0], &ctext[0], 3); + + std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size()); + + return "$2a$" + to_string(work_factor, 2) + "$" + salt_b64.substr(0, 22) + + bcrypt_base64_encode(&ctext[0], ctext.size() - 1); + } + +} + +std::string generate_bcrypt(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor) + { + return make_bcrypt(pass, rng.random_vec(16), work_factor); + } + +bool check_bcrypt(const std::string& pass, const std::string& hash) + { + if(hash.size() != 60 || + hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || + hash[3] != '$' || hash[6] != '$') + { + return false; + } + + const u16bit workfactor = to_u32bit(hash.substr(4, 2)); + + MemoryVector salt = bcrypt_base64_decode(hash.substr(7, 22)); + + const std::string compare = make_bcrypt(pass, salt, workfactor); + + return (hash == compare); + } + +} +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +const std::string MAGIC_PREFIX = "$9$"; + +const size_t WORKFACTOR_BYTES = 2; +const size_t ALGID_BYTES = 1; +const size_t SALT_BYTES = 12; // 96 bits of salt +const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output + +const size_t WORK_FACTOR_SCALE = 10000; + +MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + try + { + if(alg_id == 0) + return af.make_mac("HMAC(SHA-1)"); + else if(alg_id == 1) + return af.make_mac("HMAC(SHA-256)"); + else if(alg_id == 2) + return af.make_mac("CMAC(Blowfish)"); + } + catch(Algorithm_Not_Found) {} + + return 0; + } + +} + +std::string generate_passhash9(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor, + byte alg_id) + { + MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id); + + if(!prf) + throw Invalid_Argument("Passhash9: Algorithm id " + to_string(alg_id) + + " is not defined"); + + PKCS5_PBKDF2 kdf(prf); // takes ownership of pointer + + SecureVector salt(SALT_BYTES); + rng.randomize(&salt[0], salt.size()); + + const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + SecureVector pbkdf2_output = + kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + &salt[0], salt.size(), + kdf_iterations).bits_of(); + + Pipe pipe(new Base64_Encoder); + pipe.start_msg(); + pipe.write(alg_id); + pipe.write(get_byte(0, work_factor)); + pipe.write(get_byte(1, work_factor)); + pipe.write(salt); + pipe.write(pbkdf2_output); + pipe.end_msg(); + + return MAGIC_PREFIX + pipe.read_all_as_string(); + } + +bool check_passhash9(const std::string& pass, const std::string& hash) + { + const size_t BINARY_LENGTH = + ALGID_BYTES + + WORKFACTOR_BYTES + + PASSHASH9_PBKDF_OUTPUT_LEN + + SALT_BYTES; + + const size_t BASE64_LENGTH = + MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; + + if(hash.size() != BASE64_LENGTH) + return false; + + for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) + if(hash[i] != MAGIC_PREFIX[i]) + return false; + + Pipe pipe(new Base64_Decoder); + pipe.start_msg(); + pipe.write(hash.c_str() + MAGIC_PREFIX.size()); + pipe.end_msg(); + + SecureVector bin = pipe.read_all(); + + if(bin.size() != BINARY_LENGTH) + return false; + + byte alg_id = bin[0]; + + const size_t kdf_iterations = + WORK_FACTOR_SCALE * load_be(&bin[ALGID_BYTES], 0); + + if(kdf_iterations == 0) + return false; + + MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id); + + if(pbkdf_prf == 0) + return false; // unknown algorithm, reject + + PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer + + SecureVector cmp = kdf.derive_key( + PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, + kdf_iterations).bits_of(); + + return same_mem(&cmp[0], + &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES], + PASSHASH9_PBKDF_OUTPUT_LEN); + } + +} +/* +* PBE Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_PBE_PKCS_V15) +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) +#endif + +namespace Botan { + +/* +* Get an encryption PBE, set new parameters +*/ +PBE* get_pbe(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + const std::string pbe = request.algo_name(); + std::string digest_name = request.arg(0); + const std::string cipher = request.arg(1); + + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE: Invalid cipher spec " + cipher); + + const std::string cipher_algo = global_state().deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(cipher_mode != "CBC") + throw Invalid_Argument("PBE: Invalid cipher mode " + cipher); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo); + if(!block_cipher) + throw Algorithm_Not_Found(cipher_algo); + + const HashFunction* hash_function = af.prototype_hash_function(digest_name); + if(!hash_function) + throw Algorithm_Not_Found(digest_name); + + if(request.arg_count() != 2) + throw Invalid_Algorithm_Name(algo_spec); + +#if defined(BOTAN_HAS_PBE_PKCS_V15) + if(pbe == "PBE-PKCS5v15") + return new PBE_PKCS5v15(block_cipher->clone(), + hash_function->clone(), + ENCRYPTION); +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) + if(pbe == "PBE-PKCS5v20") + return new PBE_PKCS5v20(block_cipher->clone(), + hash_function->clone()); +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Get a decryption PBE, decode parameters +*/ +PBE* get_pbe(const OID& pbe_oid, DataSource& params) + { + SCAN_Name request(OIDS::lookup(pbe_oid)); + + const std::string pbe = request.algo_name(); + +#if defined(BOTAN_HAS_PBE_PKCS_V15) + if(pbe == "PBE-PKCS5v15") + { + if(request.arg_count() != 2) + throw Invalid_Algorithm_Name(request.as_string()); + + std::string digest_name = request.arg(0); + const std::string cipher = request.arg(1); + + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Invalid_Argument("PBE: Invalid cipher spec " + cipher); + + const std::string cipher_algo = global_state().deref_alias(cipher_spec[0]); + const std::string cipher_mode = cipher_spec[1]; + + if(cipher_mode != "CBC") + throw Invalid_Argument("PBE: Invalid cipher mode " + cipher); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo); + if(!block_cipher) + throw Algorithm_Not_Found(cipher_algo); + + const HashFunction* hash_function = + af.prototype_hash_function(digest_name); + + if(!hash_function) + throw Algorithm_Not_Found(digest_name); + + PBE* pbe = new PBE_PKCS5v15(block_cipher->clone(), + hash_function->clone(), + DECRYPTION); + pbe->decode_params(params); + return pbe; + } +#endif + +#if defined(BOTAN_HAS_PBE_PKCS_V20) + if(pbe == "PBE-PKCS5v20") + return new PBE_PKCS5v20(params); +#endif + + throw Algorithm_Not_Found(pbe_oid.as_string()); + } + +} +/* +* PKCS #5 PBES1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Encrypt some bytes using PBES1 +*/ +void PBE_PKCS5v15::write(const byte input[], size_t length) + { + pipe.write(input, length); + flush_pipe(true); + } + +/* +* Start encrypting with PBES1 +*/ +void PBE_PKCS5v15::start_msg() + { + if(direction == ENCRYPTION) + pipe.append(new CBC_Encryption(block_cipher->clone(), + new PKCS7_Padding, + key, iv)); + else + pipe.append(new CBC_Decryption(block_cipher->clone(), + new PKCS7_Padding, + key, iv)); + + pipe.start_msg(); + if(pipe.message_count() > 1) + pipe.set_default_msg(pipe.default_msg() + 1); + } + +/* +* Finish encrypting with PBES1 +*/ +void PBE_PKCS5v15::end_msg() + { + pipe.end_msg(); + flush_pipe(false); + pipe.reset(); + } + +/* +* Flush the pipe +*/ +void PBE_PKCS5v15::flush_pipe(bool safe_to_skip) + { + if(safe_to_skip && pipe.remaining() < 64) + return; + + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + send(buffer, got); + } + } + +/* +* Set the passphrase to use +*/ +void PBE_PKCS5v15::set_key(const std::string& passphrase) + { + PKCS5_PBKDF1 pbkdf(hash_function->clone()); + + SecureVector key_and_iv = pbkdf.derive_key(16, passphrase, + &salt[0], salt.size(), + iterations).bits_of(); + + key.resize(8); + iv.resize(8); + copy_mem(&key[0], &key_and_iv[0], 8); + copy_mem(&iv[0], &key_and_iv[8], 8); + } + +/* +* Create a new set of PBES1 parameters +*/ +void PBE_PKCS5v15::new_params(RandomNumberGenerator& rng) + { + iterations = 10000; + salt = rng.random_vec(8); + } + +/* +* Encode PKCS#5 PBES1 parameters +*/ +MemoryVector PBE_PKCS5v15::encode_params() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(iterations) + .end_cons() + .get_contents(); + } + +/* +* Decode PKCS#5 PBES1 parameters +*/ +void PBE_PKCS5v15::decode_params(DataSource& source) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(iterations) + .verify_end() + .end_cons(); + + if(salt.size() != 8) + throw Decoding_Error("PBES1: Encoded salt is not 8 octets"); + } + +/* +* Return an OID for this PBES1 type +*/ +OID PBE_PKCS5v15::get_oid() const + { + const OID base_pbes1_oid("1.2.840.113549.1.5"); + + const std::string cipher = block_cipher->name(); + const std::string digest = hash_function->name(); + + if(cipher == "DES" && digest == "MD2") + return (base_pbes1_oid + 1); + else if(cipher == "DES" && digest == "MD5") + return (base_pbes1_oid + 3); + else if(cipher == "DES" && digest == "SHA-160") + return (base_pbes1_oid + 10); + else if(cipher == "RC2" && digest == "MD2") + return (base_pbes1_oid + 4); + else if(cipher == "RC2" && digest == "MD5") + return (base_pbes1_oid + 6); + else if(cipher == "RC2" && digest == "SHA-160") + return (base_pbes1_oid + 11); + else + throw Internal_Error("PBE-PKCS5 v1.5: get_oid() has run out of options"); + } + +std::string PBE_PKCS5v15::name() const + { + return "PBE-PKCS5v15(" + block_cipher->name() + "," + + hash_function->name() + ")"; + } + +/* +* PKCS#5 v1.5 PBE Constructor +*/ +PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + Cipher_Dir dir) : + direction(dir), block_cipher(cipher), hash_function(hash) + { + if(cipher->name() != "DES" && cipher->name() != "RC2") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " + + cipher->name()); + } + + if(hash->name() != "MD2" && hash->name() != "MD5" && + hash->name() != "SHA-160") + { + throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " + + hash->name()); + } + } + +PBE_PKCS5v15::~PBE_PKCS5v15() + { + delete block_cipher; + delete hash_function; + } + +} +/* +* PKCS #5 PBES2 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Encrypt some bytes using PBES2 +*/ +void PBE_PKCS5v20::write(const byte input[], size_t length) + { + pipe.write(input, length); + flush_pipe(true); + } + +/* +* Start encrypting with PBES2 +*/ +void PBE_PKCS5v20::start_msg() + { + if(direction == ENCRYPTION) + pipe.append(new CBC_Encryption(block_cipher->clone(), + new PKCS7_Padding, + key, iv)); + else + pipe.append(new CBC_Decryption(block_cipher->clone(), + new PKCS7_Padding, + key, iv)); + + pipe.start_msg(); + if(pipe.message_count() > 1) + pipe.set_default_msg(pipe.default_msg() + 1); + } + +/* +* Finish encrypting with PBES2 +*/ +void PBE_PKCS5v20::end_msg() + { + pipe.end_msg(); + flush_pipe(false); + pipe.reset(); + } + +/* +* Flush the pipe +*/ +void PBE_PKCS5v20::flush_pipe(bool safe_to_skip) + { + if(safe_to_skip && pipe.remaining() < 64) + return; + + SecureVector buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + size_t got = pipe.read(&buffer[0], buffer.size()); + send(buffer, got); + } + } + +/* +* Set the passphrase to use +*/ +void PBE_PKCS5v20::set_key(const std::string& passphrase) + { + PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone())); + + key = pbkdf.derive_key(key_length, passphrase, + &salt[0], salt.size(), + iterations).bits_of(); + } + +/* +* Create a new set of PBES2 parameters +*/ +void PBE_PKCS5v20::new_params(RandomNumberGenerator& rng) + { + iterations = 10000; + key_length = block_cipher->maximum_keylength(); + + salt = rng.random_vec(12); + iv = rng.random_vec(block_cipher->block_size()); + } + +/* +* Encode PKCS#5 PBES2 parameters +*/ +MemoryVector PBE_PKCS5v20::encode_params() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode( + AlgorithmIdentifier("PKCS5.PBKDF2", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(iterations) + .encode(key_length) + .end_cons() + .get_contents() + ) + ) + .encode( + AlgorithmIdentifier(block_cipher->name() + "/CBC", + DER_Encoder() + .encode(iv, OCTET_STRING) + .get_contents() + ) + ) + .end_cons() + .get_contents(); + } + +/* +* Decode PKCS#5 PBES2 parameters +*/ +void PBE_PKCS5v20::decode_params(DataSource& source) + { + AlgorithmIdentifier kdf_algo, enc_algo; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(kdf_algo) + .decode(enc_algo) + .verify_end() + .end_cons(); + + if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2")) + { + BER_Decoder(kdf_algo.parameters) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(iterations) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .verify_end() + .end_cons(); + } + else + throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + + kdf_algo.oid.as_string()); + + Algorithm_Factory& af = global_state().algorithm_factory(); + + std::string cipher = OIDS::lookup(enc_algo.oid); + std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + + if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC") + throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + + cipher); + + BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end(); + + block_cipher = af.make_block_cipher(cipher_spec[0]); + hash_function = af.make_hash_function("SHA-160"); + + if(key_length == 0) + key_length = block_cipher->maximum_keylength(); + + if(salt.size() < 8) + throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); + } + +/* +* Return an OID for PBES2 +*/ +OID PBE_PKCS5v20::get_oid() const + { + return OIDS::lookup("PBE-PKCS5v20"); + } + +/* +* Check if this is a known PBES2 cipher +*/ +bool PBE_PKCS5v20::known_cipher(const std::string& algo) + { + if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256") + return true; + if(algo == "DES" || algo == "TripleDES") + return true; + return false; + } + +std::string PBE_PKCS5v20::name() const + { + return "PBE-PKCS5v20(" + block_cipher->name() + "," + + hash_function->name() + ")"; + } + +/* +* PKCS#5 v2.0 PBE Constructor +*/ +PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher, + HashFunction* digest) : + direction(ENCRYPTION), block_cipher(cipher), hash_function(digest) + { + if(!known_cipher(block_cipher->name())) + throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher->name()); + if(hash_function->name() != "SHA-160") + throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest->name()); + } + +/* +* PKCS#5 v2.0 PBE Constructor +*/ +PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION) + { + hash_function = 0; + block_cipher = 0; + decode_params(params); + } + +PBE_PKCS5v20::~PBE_PKCS5v20() + { + delete hash_function; + delete block_cipher; + } + +} +/* +* PBKDF1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Return a PKCS#5 PBKDF1 derived key +*/ +OctetString PKCS5_PBKDF1::derive_key(size_t key_len, + const std::string& passphrase, + const byte salt[], size_t salt_size, + size_t iterations) const + { + if(iterations == 0) + throw Invalid_Argument("PKCS5_PBKDF1: Invalid iteration count"); + + if(key_len > hash->output_length()) + throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long"); + + hash->update(passphrase); + hash->update(salt, salt_size); + SecureVector key = hash->final(); + + for(size_t j = 1; j != iterations; ++j) + { + hash->update(key); + hash->final(&key[0]); + } + + return OctetString(&key[0], std::min(key_len, key.size())); + } + +} +/* +* PBKDF2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Return a PKCS #5 PBKDF2 derived key +*/ +OctetString PKCS5_PBKDF2::derive_key(size_t key_len, + const std::string& passphrase, + const byte salt[], size_t salt_size, + size_t iterations) const + { + if(iterations == 0) + throw Invalid_Argument("PKCS#5 PBKDF2: Invalid iteration count"); + + try + { + mac->set_key(reinterpret_cast(passphrase.data()), + passphrase.length()); + } + catch(Invalid_Key_Length) + { + throw Exception(name() + " cannot accept passphrases of length " + + to_string(passphrase.length())); + } + + SecureVector key(key_len); + + byte* T = &key[0]; + + SecureVector U(mac->output_length()); + + u32bit counter = 1; + while(key_len) + { + size_t T_size = std::min(mac->output_length(), key_len); + + mac->update(salt, salt_size); + mac->update_be(counter); + mac->final(&U[0]); + + xor_buf(T, U, T_size); + + for(size_t j = 1; j != iterations; ++j) + { + mac->update(U); + mac->final(&U[0]); + xor_buf(T, U, T_size); + } + + key_len -= T_size; + T += T_size; + ++counter; + } + + return key; + } + +} +/* +* OpenPGP S2K +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Derive a key using the OpenPGP S2K algorithm +*/ +OctetString OpenPGP_S2K::derive_key(size_t key_len, + const std::string& passphrase, + const byte salt_buf[], size_t salt_size, + size_t iterations) const + { + SecureVector key(key_len), hash_buf; + + size_t pass = 0, generated = 0, + total_size = passphrase.size() + salt_size; + size_t to_hash = std::max(iterations, total_size); + + hash->clear(); + while(key_len > generated) + { + for(size_t j = 0; j != pass; ++j) + hash->update(0); + + size_t left = to_hash; + while(left >= total_size) + { + hash->update(salt_buf, salt_size); + hash->update(passphrase); + left -= total_size; + } + if(left <= salt_size) + hash->update(salt_buf, left); + else + { + hash->update(salt_buf, salt_size); + left -= salt_size; + hash->update(reinterpret_cast(passphrase.data()), left); + } + + hash_buf = hash->final(); + key.copy(generated, &hash_buf[0], hash->output_length()); + generated += hash->output_length(); + ++pass; + } + + return key; + } + +} +/* +* EME Base Class +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Encode a message +*/ +SecureVector EME::encode(const byte msg[], size_t msg_len, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg, msg_len, key_bits, rng); + } + +/* +* Encode a message +*/ +SecureVector EME::encode(const MemoryRegion& msg, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(&msg[0], msg.size(), key_bits, rng); + } + +/* +* Decode a message +*/ +SecureVector EME::decode(const byte msg[], size_t msg_len, + size_t key_bits) const + { + return unpad(msg, msg_len, key_bits); + } + +/* +* Decode a message +*/ +SecureVector EME::decode(const MemoryRegion& msg, + size_t key_bits) const + { + return unpad(&msg[0], msg.size(), key_bits); + } + +} +/* +* EME1 (aka OAEP) +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* EME1 Pad Operation +*/ +SecureVector EME1::pad(const byte in[], size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const + { + key_length /= 8; + + if(in_length > key_length - 2*Phash.size() - 1) + throw Invalid_Argument("EME1: Input is too large"); + + SecureVector out(key_length); + + rng.randomize(&out[0], Phash.size()); + + out.copy(Phash.size(), &Phash[0], Phash.size()); + out[out.size() - in_length - 1] = 0x01; + out.copy(out.size() - in_length, in, in_length); + + mgf->mask(&out[0], Phash.size(), + &out[Phash.size()], out.size() - Phash.size()); + + mgf->mask(&out[Phash.size()], out.size() - Phash.size(), + &out[0], Phash.size()); + + return out; + } + +/* +* EME1 Unpad Operation +*/ +SecureVector EME1::unpad(const byte in[], size_t in_length, + size_t key_length) const + { + /* + Must be careful about error messages here; if an attacker can + distinguish them, it is easy to use the differences as an oracle to + find the secret key, as described in "A Chosen Ciphertext Attack on + RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in + PKCS #1 v2.0", James Manger, Crypto 2001 + + Also have to be careful about timing attacks! Pointed out by Falko + Strenzke. + */ + + key_length /= 8; + + // Invalid input: truncate to zero length input, causing later + // checks to fail + if(in_length > key_length) + in_length = 0; + + SecureVector input(key_length); + input.copy(key_length - in_length, in, in_length); + + mgf->mask(&input[Phash.size()], input.size() - Phash.size(), + &input[0], Phash.size()); + mgf->mask(&input[0], Phash.size(), + &input[Phash.size()], input.size() - Phash.size()); + + bool waiting_for_delim = true; + bool bad_input = false; + size_t delim_idx = 2 * Phash.size(); + + /* + * GCC 4.5 on x86-64 compiles this in a way that is still vunerable + * to timing analysis. Other compilers, or GCC on other platforms, + * may or may not. + */ + for(size_t i = delim_idx; i != input.size(); ++i) + { + const bool zero_p = !input[i]; + const bool one_p = input[i] == 0x01; + + const bool add_1 = waiting_for_delim && zero_p; + + bad_input |= waiting_for_delim && !(zero_p || one_p); + + delim_idx += add_1; + + waiting_for_delim &= zero_p; + } + + // If we never saw any non-zero byte, then it's not valid input + bad_input |= waiting_for_delim; + + bad_input |= !same_mem(&input[Phash.size()], &Phash[0], Phash.size()); + + if(bad_input) + throw Decoding_Error("Invalid EME1 encoding"); + + return SecureVector(input + delim_idx + 1, + input.size() - delim_idx - 1); + } + +/* +* Return the max input size for a given key size +*/ +size_t EME1::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 2*Phash.size() + 1) + return ((keybits / 8) - 2*Phash.size() - 1); + else + return 0; + } + +/* +* EME1 Constructor +*/ +EME1::EME1(HashFunction* hash, const std::string& P) + { + Phash = hash->process(P); + mgf = new MGF1(hash); + } + +} +/* +* PKCS1 EME +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* PKCS1 Pad Operation +*/ +SecureVector EME_PKCS1v15::pad(const byte in[], size_t inlen, + size_t olen, + RandomNumberGenerator& rng) const + { + olen /= 8; + + if(olen < 10) + throw Encoding_Error("PKCS1: Output space too small"); + if(inlen > olen - 10) + throw Encoding_Error("PKCS1: Input is too large"); + + SecureVector out(olen); + + out[0] = 0x02; + for(size_t j = 1; j != olen - inlen - 1; ++j) + while(out[j] == 0) + out[j] = rng.next_byte(); + out.copy(olen - inlen, in, inlen); + + return out; + } + +/* +* PKCS1 Unpad Operation +*/ +SecureVector EME_PKCS1v15::unpad(const byte in[], size_t inlen, + size_t key_len) const + { + if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02) + throw Decoding_Error("PKCS1::unpad"); + + size_t seperator = 0; + for(size_t j = 0; j != inlen; ++j) + if(in[j] == 0) + { + seperator = j; + break; + } + if(seperator < 9) + throw Decoding_Error("PKCS1::unpad"); + + return SecureVector(in + seperator + 1, inlen - seperator - 1); + } + +/* +* Return the max input size for a given key size +*/ +size_t EME_PKCS1v15::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 10) + return ((keybits / 8) - 10); + else + return 0; + } + +} +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +SecureVector emsa1_encoding(const MemoryRegion& msg, + size_t output_bits) + { + if(8*msg.size() <= output_bits) + return msg; + + size_t shift = 8*msg.size() - output_bits; + + size_t byte_shift = shift / 8, bit_shift = shift % 8; + SecureVector digest(msg.size() - byte_shift); + + for(size_t j = 0; j != msg.size() - byte_shift; ++j) + digest[j] = msg[j]; + + if(bit_shift) + { + byte carry = 0; + for(size_t j = 0; j != digest.size(); ++j) + { + byte temp = digest[j]; + digest[j] = (temp >> bit_shift) | carry; + carry = (temp << (8 - bit_shift)); + } + } + return digest; + } + +} + +/* +* EMSA1 Update Operation +*/ +void EMSA1::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA1::raw_data() + { + return hash->final(); + } + +/* +* EMSA1 Encode Operation +*/ +SecureVector EMSA1::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash->output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + return emsa1_encoding(msg, output_bits); + } + +/* +* EMSA1 Decode/Verify Operation +*/ +bool EMSA1::verify(const MemoryRegion& coded, + const MemoryRegion& raw, size_t key_bits) + { + try { + if(raw.size() != hash->output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + + SecureVector our_coding = emsa1_encoding(raw, key_bits); + + if(our_coding == coded) return true; + if(our_coding[0] != 0) return false; + if(our_coding.size() <= coded.size()) return false; + + size_t offset = 0; + while(our_coding[offset] == 0 && offset < our_coding.size()) + ++offset; + if(our_coding.size() - offset != coded.size()) + return false; + + for(size_t j = 0; j != coded.size(); ++j) + if(coded[j] != our_coding[j+offset]) + return false; + + return true; + } + catch(Invalid_Argument) + { + return false; + } + } + +} +/* +* EMSA1 BSI +* (C) 1999-2008 Jack Lloyd +* 2008 Falko Strenzke, FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* EMSA1 BSI Encode Operation +*/ +SecureVector EMSA1_BSI::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash_ptr()->output_length()) + throw Encoding_Error("EMSA1_BSI::encoding_of: Invalid size for input"); + + if(8*msg.size() <= output_bits) + return msg; + + throw Encoding_Error("EMSA1_BSI::encoding_of: max key input size exceeded"); + } + +} +/* +* EMSA2 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* EMSA2 Encode Operation +*/ +SecureVector emsa2_encoding(const MemoryRegion& msg, + size_t output_bits, + const MemoryRegion& empty_hash, + byte hash_id) + { + const size_t HASH_SIZE = empty_hash.size(); + + size_t output_length = (output_bits + 1) / 8; + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("EMSA2::encoding_of: Bad input length"); + if(output_length < HASH_SIZE + 4) + throw Encoding_Error("EMSA2::encoding_of: Output length is too small"); + + bool empty = true; + for(size_t j = 0; j != HASH_SIZE; ++j) + if(empty_hash[j] != msg[j]) + empty = false; + + SecureVector output(output_length); + + output[0] = (empty ? 0x4B : 0x6B); + output[output_length - 3 - HASH_SIZE] = 0xBA; + set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB); + output.copy(output_length - (HASH_SIZE + 2), &msg[0], msg.size()); + output[output_length-2] = hash_id; + output[output_length-1] = 0xCC; + + return output; + } + +} + +/* +* EMSA2 Update Operation +*/ +void EMSA2::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA2::raw_data() + { + return hash->final(); + } + +/* +* EMSA2 Encode Operation +*/ +SecureVector EMSA2::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa2_encoding(msg, output_bits, empty_hash, hash_id); + } + +/* +* EMSA2 Verify Operation +*/ +bool EMSA2::verify(const MemoryRegion& coded, + const MemoryRegion& raw, + size_t key_bits) + { + try + { + return (coded == emsa2_encoding(raw, key_bits, + empty_hash, hash_id)); + } + catch(...) + { + return false; + } + } + +/* +* EMSA2 Constructor +*/ +EMSA2::EMSA2(HashFunction* hash_in) : hash(hash_in) + { + empty_hash = hash->final(); + + hash_id = ieee1363_hash_id(hash->name()); + + if(hash_id == 0) + { + const std::string hashName = hash->name(); + delete hash; + throw Encoding_Error("EMSA2 cannot be used with " + hashName); + } + } + +} +/* +* EMSA3 and EMSA3_Raw +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* EMSA3 Encode Operation +*/ +SecureVector emsa3_encoding(const MemoryRegion& msg, + size_t output_bits, + const byte hash_id[], + size_t hash_id_length) + { + size_t output_length = output_bits / 8; + if(output_length < hash_id_length + msg.size() + 10) + throw Encoding_Error("emsa3_encoding: Output length is too small"); + + SecureVector T(output_length); + const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2; + + T[0] = 0x01; + set_mem(&T[1], P_LENGTH, 0xFF); + T[P_LENGTH+1] = 0x00; + T.copy(P_LENGTH+2, hash_id, hash_id_length); + T.copy(output_length-msg.size(), &msg[0], msg.size()); + return T; + } + +} + +/* +* EMSA3 Update Operation +*/ +void EMSA3::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA3::raw_data() + { + return hash->final(); + } + +/* +* EMSA3 Encode Operation +*/ +SecureVector EMSA3::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash->output_length()) + throw Encoding_Error("EMSA3::encoding_of: Bad input length"); + + return emsa3_encoding(msg, output_bits, + &hash_id[0], hash_id.size()); + } + +/* +* Default signature decoding +*/ +bool EMSA3::verify(const MemoryRegion& coded, + const MemoryRegion& raw, + size_t key_bits) + { + if(raw.size() != hash->output_length()) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, + &hash_id[0], hash_id.size())); + } + catch(...) + { + return false; + } + } + +/* +* EMSA3 Constructor +*/ +EMSA3::EMSA3(HashFunction* hash_in) : hash(hash_in) + { + hash_id = pkcs_hash_id(hash->name()); + } + +/* +* EMSA3 Destructor +*/ +EMSA3::~EMSA3() + { + delete hash; + } + +/* +* EMSA3_Raw Update Operation +*/ +void EMSA3_Raw::update(const byte input[], size_t length) + { + message += std::make_pair(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA3_Raw::raw_data() + { + SecureVector ret; + std::swap(ret, message); + return ret; + } + +/* +* EMSA3_Raw Encode Operation +*/ +SecureVector EMSA3_Raw::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa3_encoding(msg, output_bits, 0, 0); + } + +/* +* Default signature decoding +*/ +bool EMSA3_Raw::verify(const MemoryRegion& coded, + const MemoryRegion& raw, + size_t key_bits) + { + try + { + return (coded == emsa3_encoding(raw, key_bits, 0, 0)); + } + catch(...) + { + return false; + } + } + +} +/* +* EMSA4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* EMSA4 Update Operation +*/ +void EMSA4::update(const byte input[], size_t length) + { + hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA4::raw_data() + { + return hash->final(); + } + +/* +* EMSA4 Encode Operation +*/ +SecureVector EMSA4::encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + const size_t HASH_SIZE = hash->output_length(); + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("EMSA4::encoding_of: Bad input length"); + if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) + throw Encoding_Error("EMSA4::encoding_of: Output length is too small"); + + const size_t output_length = (output_bits + 7) / 8; + + SecureVector salt = rng.random_vec(SALT_SIZE); + + for(size_t j = 0; j != 8; ++j) + hash->update(0); + hash->update(msg); + hash->update(salt, SALT_SIZE); + SecureVector H = hash->final(); + + SecureVector EM(output_length); + + EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; + EM.copy(output_length - 1 - HASH_SIZE - SALT_SIZE, salt, SALT_SIZE); + mgf->mask(H, HASH_SIZE, EM, output_length - HASH_SIZE - 1); + EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); + EM.copy(output_length - 1 - HASH_SIZE, H, HASH_SIZE); + EM[output_length-1] = 0xBC; + + return EM; + } + +/* +* EMSA4 Decode/Verify Operation +*/ +bool EMSA4::verify(const MemoryRegion& const_coded, + const MemoryRegion& raw, size_t key_bits) + { + const size_t HASH_SIZE = hash->output_length(); + const size_t KEY_BYTES = (key_bits + 7) / 8; + + if(key_bits < 8*HASH_SIZE + 9) + return false; + + if(raw.size() != HASH_SIZE) + return false; + + if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1) + return false; + + if(const_coded[const_coded.size()-1] != 0xBC) + return false; + + SecureVector coded = const_coded; + if(coded.size() < KEY_BYTES) + { + SecureVector temp(KEY_BYTES); + temp.copy(KEY_BYTES - coded.size(), coded, coded.size()); + coded = temp; + } + + const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; + if(TOP_BITS > 8 - high_bit(coded[0])) + return false; + + SecureVector DB(&coded[0], coded.size() - HASH_SIZE - 1); + SecureVector H(&coded[coded.size() - HASH_SIZE - 1], HASH_SIZE); + + mgf->mask(H, H.size(), DB, coded.size() - H.size() - 1); + DB[0] &= 0xFF >> TOP_BITS; + + size_t salt_offset = 0; + for(size_t j = 0; j != DB.size(); ++j) + { + if(DB[j] == 0x01) + { salt_offset = j + 1; break; } + if(DB[j]) + return false; + } + if(salt_offset == 0) + return false; + + SecureVector salt(&DB[salt_offset], DB.size() - salt_offset); + + for(size_t j = 0; j != 8; ++j) + hash->update(0); + hash->update(raw); + hash->update(salt); + SecureVector H2 = hash->final(); + + return (H == H2); + } + +/* +* EMSA4 Constructor +*/ +EMSA4::EMSA4(HashFunction* h) : + SALT_SIZE(h->output_length()), hash(h) + { + mgf = new MGF1(hash->clone()); + } + +/* +* EMSA4 Constructor +*/ +EMSA4::EMSA4(HashFunction* h, size_t salt_size) : + SALT_SIZE(salt_size), hash(h) + { + mgf = new MGF1(hash->clone()); + } + +} +/* +* EMSA-Raw +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* EMSA-Raw Encode Operation +*/ +void EMSA_Raw::update(const byte input[], size_t length) + { + message += std::make_pair(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +SecureVector EMSA_Raw::raw_data() + { + SecureVector output; + std::swap(message, output); + return output; + } + +/* +* EMSA-Raw Encode Operation +*/ +SecureVector EMSA_Raw::encoding_of(const MemoryRegion& msg, + size_t, + RandomNumberGenerator&) + { + return msg; + } + +/* +* EMSA-Raw Verify Operation +*/ +bool EMSA_Raw::verify(const MemoryRegion& coded, + const MemoryRegion& raw, + size_t) + { + if(coded.size() == raw.size()) + return (coded == raw); + + if(coded.size() > raw.size()) + return false; + + // handle zero padding differences + const size_t leading_zeros_expected = raw.size() - coded.size(); + + bool same_modulo_leading_zeros = true; + + for(size_t i = 0; i != leading_zeros_expected; ++i) + if(raw[i]) + same_modulo_leading_zeros = false; + + if(!same_mem(&coded[0], &raw[leading_zeros_expected], coded.size())) + same_modulo_leading_zeros = false; + + return same_modulo_leading_zeros; + } + +} +/* +* Hash Function Identification +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +const byte MD2_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 }; + +const byte MD5_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +const byte RIPEMD_128_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x02, 0x05, 0x00, 0x04, 0x14 }; + +const byte RIPEMD_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x01, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, +0x1A, 0x05, 0x00, 0x04, 0x14 }; + +const byte SHA_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C }; + +const byte SHA_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; + +const byte SHA_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; + +const byte SHA_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + +const byte TIGER_PKCS_ID[] = { +0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, +0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; + +} + +/* +* HashID as specified by PKCS +*/ +MemoryVector pkcs_hash_id(const std::string& name) + { + // Special case for SSL/TLS RSA signatures + if(name == "Parallel(MD5,SHA-160)") + return MemoryVector(); + + if(name == "MD2") + return MemoryVector(MD2_PKCS_ID, sizeof(MD2_PKCS_ID)); + if(name == "MD5") + return MemoryVector(MD5_PKCS_ID, sizeof(MD5_PKCS_ID)); + if(name == "RIPEMD-128") + return MemoryVector(RIPEMD_128_PKCS_ID, sizeof(RIPEMD_128_PKCS_ID)); + if(name == "RIPEMD-160") + return MemoryVector(RIPEMD_160_PKCS_ID, sizeof(RIPEMD_160_PKCS_ID)); + if(name == "SHA-160") + return MemoryVector(SHA_160_PKCS_ID, sizeof(SHA_160_PKCS_ID)); + if(name == "SHA-224") + return MemoryVector(SHA_224_PKCS_ID, sizeof(SHA_224_PKCS_ID)); + if(name == "SHA-256") + return MemoryVector(SHA_256_PKCS_ID, sizeof(SHA_256_PKCS_ID)); + if(name == "SHA-384") + return MemoryVector(SHA_384_PKCS_ID, sizeof(SHA_384_PKCS_ID)); + if(name == "SHA-512") + return MemoryVector(SHA_512_PKCS_ID, sizeof(SHA_512_PKCS_ID)); + if(name == "Tiger(24,3)") + return MemoryVector(TIGER_PKCS_ID, sizeof(TIGER_PKCS_ID)); + + throw Invalid_Argument("No PKCS #1 identifier for " + name); + } + +/* +* HashID as specified by IEEE 1363/X9.31 +*/ +byte ieee1363_hash_id(const std::string& name) + { + if(name == "SHA-160") return 0x33; + + if(name == "SHA-224") return 0x38; + if(name == "SHA-256") return 0x34; + if(name == "SHA-384") return 0x36; + if(name == "SHA-512") return 0x35; + + if(name == "RIPEMD-160") return 0x31; + if(name == "RIPEMD-128") return 0x32; + + if(name == "Whirlpool") return 0x37; + + return 0; + } + +} +/* +* Blinding for public key operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Blinder Constructor +*/ +Blinder::Blinder(const BigInt& e, const BigInt& d, const BigInt& n) + { + if(e < 1 || d < 1 || n < 1) + throw Invalid_Argument("Blinder: Arguments too small"); + + reducer = Modular_Reducer(n); + this->e = e; + this->d = d; + } + +/* +* Blind a number +*/ +BigInt Blinder::blind(const BigInt& i) const + { + if(!reducer.initialized()) + return i; + + e = reducer.square(e); + d = reducer.square(d); + return reducer.multiply(i, e); + } + +/* +* Unblind a number +*/ +BigInt Blinder::unblind(const BigInt& i) const + { + if(!reducer.initialized()) + return i; + return reducer.multiply(i, d); + } + +} +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* DH_PublicKey Constructor +*/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Return the public value for key agreement +*/ +MemoryVector DH_PublicKey::public_value() const + { + return BigInt::encode_1363(y, group_p().bytes()); + } + +/* +* Create a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + const BigInt& p = group_p(); + x.randomize(rng, 2 * dl_work_factor(p.bits())); + } + + if(y == 0) + y = power_mod(group_g(), x, group_p()); + + if(x == 0) + gen_check(rng); + else + load_check(rng); + } + +/* +* Load a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Return the public value for key agreement +*/ +MemoryVector DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +DH_KA_Operation::DH_KA_Operation(const DH_PrivateKey& dh) : + p(dh.group_p()), powermod_x_p(dh.get_x(), p) + { + BigInt k(global_state().global_rng(), p.bits() - 1); + blinder = Blinder(k, powermod_x_p(inverse_mod(k, p)), p); + } + +SecureVector DH_KA_Operation::agree(const byte w[], size_t w_len) + { + BigInt input = BigInt::decode(w, w_len); + + BigInt r = blinder.unblind(powermod_x_p(blinder.blind(input))); + + return BigInt::encode_1363(r, p.bytes()); + } + +} +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + group.DER_encode(group_format())); + } + +MemoryVector DL_Scheme_PublicKey::x509_subject_public_key() const + { + return DER_Encoder().encode(y).get_contents(); + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + DL_Group::Format format) + { + DataSource_Memory source(alg_id.parameters); + group.BER_decode(source, format); + + BER_Decoder(key_bits).decode(y); + } + +MemoryVector DL_Scheme_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder().encode(x).get_contents(); + } + +DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + DL_Group::Format format) + { + DataSource_Memory source(alg_id.parameters); + group.BER_decode(source, format); + + BER_Decoder(key_bits).decode(x); + } + +/* +* Check Public DL Parameters +*/ +bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(y < 2 || y >= group_p()) + return false; + if(!group.verify_group(rng, strong)) + return false; + return true; + } + +/* +* Check DL Scheme Private Parameters +*/ +bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + const BigInt& p = group_p(); + const BigInt& g = group_g(); + + if(y < 2 || y >= p || x < 2 || x >= p) + return false; + if(!group.verify_group(rng, strong)) + return false; + + if(!strong) + return true; + + if(y != power_mod(g, x, p)) + return false; + + return true; + } + +} +/* +* Discrete Logarithm Parameters +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group() + { + initialized = false; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const std::string& type) + { + std::string grp_contents = global_state().get("dl", type); + + if(grp_contents == "") + throw Invalid_Argument("DL_Group: Unknown group " + type); + + DataSource_Memory pem(grp_contents); + PEM_decode(pem); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + PrimeType type, size_t pbits, size_t qbits) + { + if(pbits < 512) + throw Invalid_Argument("DL_Group: prime size " + to_string(pbits) + + " is too small"); + + if(type == Strong) + { + p = random_safe_prime(rng, pbits); + q = (p - 1) / 2; + g = 2; + } + else if(type == Prime_Subgroup) + { + if(!qbits) + qbits = 2 * dl_work_factor(pbits); + + q = random_prime(rng, qbits); + BigInt X; + while(p.bits() != pbits || !check_prime(p, rng)) + { + X.randomize(rng, pbits); + p = X - (X % (2*q) - 1); + } + + g = make_dsa_generator(p, q); + } + else if(type == DSA_Kosherizer) + { + qbits = qbits ? qbits : ((pbits <= 1024) ? 160 : 256); + + generate_dsa_primes(rng, + global_state().algorithm_factory(), + p, q, + pbits, qbits); + + g = make_dsa_generator(p, q); + } + + initialized = true; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + const MemoryRegion& seed, size_t pbits, size_t qbits) + { + if(!generate_dsa_primes(rng, + global_state().algorithm_factory(), + p, q, pbits, qbits, seed)) + throw Invalid_Argument("DL_Group: The seed given does not " + "generate a DSA group"); + + g = make_dsa_generator(p, q); + + initialized = true; + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& g1) + { + initialize(p1, 0, g1); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + initialize(p1, q1, g1); + } + +/* +* DL_Group Initializer +*/ +void DL_Group::initialize(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + if(p1 < 3) + throw Invalid_Argument("DL_Group: Prime invalid"); + if(g1 < 2 || g1 >= p1) + throw Invalid_Argument("DL_Group: Generator invalid"); + if(q1 < 0 || q1 >= p1) + throw Invalid_Argument("DL_Group: Subgroup invalid"); + + p = p1; + g = g1; + q = q1; + + initialized = true; + } + +/* +* Verify that the group has been set +*/ +void DL_Group::init_check() const + { + if(!initialized) + throw Invalid_State("DLP group cannot be used uninitialized"); + } + +/* +* Verify the parameters +*/ +bool DL_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + init_check(); + + if(g < 2 || p < 3 || q < 0) + return false; + if((q != 0) && ((p - 1) % q != 0)) + return false; + + if(!strong) + return true; + + if(!check_prime(p, rng)) + return false; + if((q > 0) && !check_prime(q, rng)) + return false; + return true; + } + +/* +* Return the prime +*/ +const BigInt& DL_Group::get_p() const + { + init_check(); + return p; + } + +/* +* Return the generator +*/ +const BigInt& DL_Group::get_g() const + { + init_check(); + return g; + } + +/* +* Return the subgroup +*/ +const BigInt& DL_Group::get_q() const + { + init_check(); + if(q == 0) + throw Invalid_State("DLP group has no q prime specified"); + return q; + } + +/* +* DER encode the parameters +*/ +SecureVector DL_Group::DER_encode(Format format) const + { + init_check(); + + if((q == 0) && (format != PKCS_3)) + throw Encoding_Error("The ANSI DL parameter formats require a subgroup"); + + if(format == ANSI_X9_57) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(q) + .encode(g) + .end_cons() + .get_contents(); + } + else if(format == ANSI_X9_42) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .encode(q) + .end_cons() + .get_contents(); + } + else if(format == PKCS_3) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .end_cons() + .get_contents(); + } + + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + } + +/* +* PEM encode the parameters +*/ +std::string DL_Group::PEM_encode(Format format) const + { + SecureVector encoding = DER_encode(format); + if(format == PKCS_3) + return PEM_Code::encode(encoding, "DH PARAMETERS"); + else if(format == ANSI_X9_57) + return PEM_Code::encode(encoding, "DSA PARAMETERS"); + else if(format == ANSI_X9_42) + return PEM_Code::encode(encoding, "X942 DH PARAMETERS"); + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + } + +/* +* Decode BER encoded parameters +*/ +void DL_Group::BER_decode(DataSource& source, Format format) + { + BigInt new_p, new_q, new_g; + + BER_Decoder decoder(source); + BER_Decoder ber = decoder.start_cons(SEQUENCE); + + if(format == ANSI_X9_57) + { + ber.decode(new_p) + .decode(new_q) + .decode(new_g) + .verify_end(); + } + else if(format == ANSI_X9_42) + { + ber.decode(new_p) + .decode(new_g) + .decode(new_q) + .discard_remaining(); + } + else if(format == PKCS_3) + { + ber.decode(new_p) + .decode(new_g) + .discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + + initialize(new_p, new_q, new_g); + } + +/* +* Decode PEM encoded parameters +*/ +void DL_Group::PEM_decode(DataSource& source) + { + std::string label; + DataSource_Memory ber(PEM_Code::decode(source, label)); + + if(label == "DH PARAMETERS") + BER_decode(ber, PKCS_3); + else if(label == "DSA PARAMETERS") + BER_decode(ber, ANSI_X9_57); + else if(label == "X942 DH PARAMETERS") + BER_decode(ber, ANSI_X9_42); + else + throw Decoding_Error("DL_Group: Invalid PEM label " + label); + } + +/* +* Create generator of the q-sized subgroup (DSA style generator) +*/ +BigInt DL_Group::make_dsa_generator(const BigInt& p, const BigInt& q) + { + BigInt g, e = (p - 1) / q; + + BOTAN_ASSERT(e > 0, "q does not divide p, invalid group"); + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + g = power_mod(PRIMES[i], e, p); + if(g > 1) + return g; + } + + throw Internal_Error("DL_Group: Couldn't create a suitable generator"); + } + +} +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* DLIES_Encryptor Constructor +*/ +DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& key, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + size_t mac_kl) : + ka(key, "Raw"), + kdf(kdf_obj), + mac(mac_obj), + mac_keylen(mac_kl) + { + my_key = key.public_value(); + } + +DLIES_Encryptor::~DLIES_Encryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Encryption +*/ +SecureVector DLIES_Encryptor::enc(const byte in[], size_t length, + RandomNumberGenerator&) const + { + if(length > maximum_input_size()) + throw Invalid_Argument("DLIES: Plaintext too large"); + if(other_key.empty()) + throw Invalid_State("DLIES: The other key was never set"); + + SecureVector out(my_key.size() + length + mac->output_length()); + out.copy(&my_key[0], my_key.size()); + out.copy(my_key.size(), in, length); + + SecureVector vz = my_key; + vz += ka.derive_key(0, other_key).bits_of(); + + const size_t K_LENGTH = length + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz); + + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + byte* C = &out[my_key.size()]; + + xor_buf(C, K.begin() + mac_keylen, length); + mac->set_key(K.begin(), mac_keylen); + + mac->update(C, length); + for(size_t j = 0; j != 8; ++j) + mac->update(0); + + mac->final(C + length); + + return out; + } + +/* +* Set the other parties public key +*/ +void DLIES_Encryptor::set_other_key(const MemoryRegion& ok) + { + other_key = ok; + } + +/* +* Return the max size, in bytes, of a message +*/ +size_t DLIES_Encryptor::maximum_input_size() const + { + return 32; + } + +/* +* DLIES_Decryptor Constructor +*/ +DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& key, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + size_t mac_kl) : + ka(key, "Raw"), + kdf(kdf_obj), + mac(mac_obj), + mac_keylen(mac_kl) + { + my_key = key.public_value(); + } + +DLIES_Decryptor::~DLIES_Decryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Decryption +*/ +SecureVector DLIES_Decryptor::dec(const byte msg[], size_t length) const + { + if(length < my_key.size() + mac->output_length()) + throw Decoding_Error("DLIES decryption: ciphertext is too short"); + + const size_t CIPHER_LEN = length - my_key.size() - mac->output_length(); + + SecureVector v(msg, my_key.size()); + SecureVector C(msg + my_key.size(), CIPHER_LEN); + SecureVector T(msg + my_key.size() + CIPHER_LEN, mac->output_length()); + + SecureVector vz(msg, my_key.size()); + vz += ka.derive_key(0, v).bits_of(); + + const size_t K_LENGTH = C.size() + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz); + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + + mac->set_key(K.begin(), mac_keylen); + mac->update(C); + for(size_t j = 0; j != 8; ++j) + mac->update(0); + SecureVector T2 = mac->final(); + if(T != T2) + throw Decoding_Error("DLIES: message authentication failed"); + + xor_buf(C, K.begin() + mac_keylen, C.size()); + + return C; + } + +} +/* +* DSA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* DSA_PublicKey Constructor +*/ +DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Create a DSA private key +*/ +DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x = BigInt::random_integer(rng, 2, group_q() - 1); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Check Private DSA Parameters +*/ +bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +DSA_Signature_Operation::DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + q(dsa.group_q()), + x(dsa.get_x()), + powermod_g_p(dsa.group_g(), dsa.group_p()), + mod_q(dsa.group_q()) + { + } + +SecureVector +DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt i(msg, msg_len); + BigInt r = 0, s = 0; + + while(r == 0 || s == 0) + { + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + r = mod_q.reduce(powermod_g_p(k)); + s = mod_q.multiply(inverse_mod(k, q), mul_add(x, r, i)); + } + + SecureVector output(2*q.bytes()); + r.binary_encode(&output[output.size() / 2 - r.bytes()]); + s.binary_encode(&output[output.size() - s.bytes()]); + return output; + } + +DSA_Verification_Operation::DSA_Verification_Operation(const DSA_PublicKey& dsa) : + q(dsa.group_q()), y(dsa.get_y()) + { + powermod_g_p = Fixed_Base_Power_Mod(dsa.group_g(), dsa.group_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, dsa.group_p()); + mod_p = Modular_Reducer(dsa.group_p()); + mod_q = Modular_Reducer(dsa.group_q()); + } + +bool DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const BigInt& q = mod_q.get_modulus(); + + if(sig_len != 2*q.bytes() || msg_len > q.bytes()) + return false; + + BigInt r(sig, q.bytes()); + BigInt s(sig + q.bytes(), q.bytes()); + BigInt i(msg, msg_len); + + if(r <= 0 || r >= q || s <= 0 || s >= q) + return false; + + s = inverse_mod(s, q); + s = mod_p.multiply(powermod_g_p(mod_q.multiply(s, i)), + powermod_y_p(mod_q.multiply(s, r))); + + return (mod_q.reduce(s) == r); + } + +} +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +EC_Group::EC_Group(const OID& domain_oid) + { + std::string pem = + global_state().get("ec", OIDS::lookup(domain_oid)); + + if(pem == "") + throw Lookup_Error("No ECC domain data for " + domain_oid.as_string()); + + *this = EC_Group(pem); + oid = domain_oid.as_string(); + } + +EC_Group::EC_Group(const std::string& str) + { + if(str == "") + return; // no initialization / uninitialized + + try + { + DataSource_Memory input(str); + + SecureVector ber = + PEM_Code::decode_check_label(input, "EC PARAMETERS"); + + *this = EC_Group(ber); + } + catch(Decoding_Error) // hmm, not PEM? + { + *this = EC_Group(OIDS::lookup(str)); + } + } + +EC_Group::EC_Group(const MemoryRegion& ber_data) + { + BER_Decoder ber(ber_data); + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag == NULL_TAG) + throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters"); + else if(obj.type_tag == OBJECT_ID) + { + OID dom_par_oid; + BER_Decoder(ber_data).decode(dom_par_oid); + *this = EC_Group(dom_par_oid); + } + else if(obj.type_tag == SEQUENCE) + { + BigInt p, a, b; + SecureVector sv_base_point; + + BER_Decoder(ber_data) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown ECC param version code") + .start_cons(SEQUENCE) + .decode_and_check(OID("1.2.840.10045.1.1"), + "Only prime ECC fields supported") + .decode(p) + .end_cons() + .start_cons(SEQUENCE) + .decode_octet_string_bigint(a) + .decode_octet_string_bigint(b) + .end_cons() + .decode(sv_base_point, OCTET_STRING) + .decode(order) + .decode(cofactor) + .end_cons() + .verify_end(); + + curve = CurveGFp(p, a, b); + base_point = OS2ECP(sv_base_point, curve); + } + else + throw Decoding_Error("Unexpected tag while decoding ECC domain params"); + } + +SecureVector +EC_Group::DER_encode(EC_Group_Encoding form) const + { + if(form == EC_DOMPAR_ENC_EXPLICIT) + { + const size_t ecpVers1 = 1; + OID curve_type("1.2.840.10045.1.1"); + + const size_t p_bytes = curve.get_p().bytes(); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(ecpVers1) + .start_cons(SEQUENCE) + .encode(curve_type) + .encode(curve.get_p()) + .end_cons() + .start_cons(SEQUENCE) + .encode(BigInt::encode_1363(curve.get_a(), p_bytes), + OCTET_STRING) + .encode(BigInt::encode_1363(curve.get_b(), p_bytes), + OCTET_STRING) + .end_cons() + .encode(EC2OSP(base_point, PointGFp::UNCOMPRESSED), OCTET_STRING) + .encode(order) + .encode(cofactor) + .end_cons() + .get_contents(); + } + else if(form == EC_DOMPAR_ENC_OID) + return DER_Encoder().encode(get_oid()).get_contents(); + else if(form == EC_DOMPAR_ENC_IMPLICITCA) + return DER_Encoder().encode_null().get_contents(); + else + throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); + } + +std::string EC_Group::PEM_encode() const + { + SecureVector der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); + return PEM_Code::encode(der, "EC PARAMETERS"); + } + +} +/* +* ECC Key implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point) : + domain_params(dom_par), public_key(pub_point), + domain_encoding(EC_DOMPAR_ENC_EXPLICIT) + { + if(domain().get_curve() != public_point().get_curve()) + throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); + } + +EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) + { + domain_params = EC_Group(alg_id.parameters); + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + public_key = OS2ECP(key_bits, domain().get_curve()); + } + +bool EC_PublicKey::check_key(RandomNumberGenerator&, + bool) const + { + return public_point().on_the_curve(); + } + +AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), DER_domain()); + } + +MemoryVector EC_PublicKey::x509_subject_public_key() const + { + return EC2OSP(public_point(), PointGFp::COMPRESSED); + } + +void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) + { + if(form != EC_DOMPAR_ENC_EXPLICIT && + form != EC_DOMPAR_ENC_IMPLICITCA && + form != EC_DOMPAR_ENC_OID) + throw Invalid_Argument("Invalid encoding form for EC-key object specified"); + + if((form == EC_DOMPAR_ENC_OID) && (domain_params.get_oid() == "")) + throw Invalid_Argument("Invalid encoding form OID specified for " + "EC-key object whose corresponding domain " + "parameters are without oid"); + + domain_encoding = form; + } + +const BigInt& EC_PrivateKey::private_value() const + { + if(private_key == 0) + throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); + + return private_key; + } + +/** +* EC_PrivateKey constructor +*/ +EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& ec_group, + const BigInt& x) + { + domain_params = ec_group; + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if(x == 0) + private_key = BigInt::random_integer(rng, 1, domain().get_order()); + else + private_key = x; + + public_key = domain().get_base_point() * private_key; + + BOTAN_ASSERT(public_key.on_the_curve(), + "ECC private key was not on the curve"); + } + +MemoryVector EC_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(1)) + .encode(BigInt::encode_1363(private_key, private_key.bytes()), + OCTET_STRING) + .end_cons() + .get_contents(); + } + +EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) + { + domain_params = EC_Group(alg_id.parameters); + domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown version code for ECC key") + .decode_octet_string_bigint(private_key) + .verify_end() + .end_cons(); + + public_key = domain().get_base_point() * private_key; + + BOTAN_ASSERT(public_key.on_the_curve(), + "Loaded ECC private key not on the curve"); + } + +} +/* +* ECDH implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +ECDH_KA_Operation::ECDH_KA_Operation(const ECDH_PrivateKey& key) : + curve(key.domain().get_curve()), + cofactor(key.domain().get_cofactor()) + { + l_times_priv = inverse_mod(cofactor, key.domain().get_order()) * + key.private_value(); + } + +SecureVector ECDH_KA_Operation::agree(const byte w[], size_t w_len) + { + PointGFp point = OS2ECP(w, w_len, curve); + + PointGFp S = (cofactor * point) * l_times_priv; + + BOTAN_ASSERT(S.on_the_curve(), + "ECDH agreed value not on the curve"); + + return BigInt::encode_1363(S.get_affine_x(), + curve.get_p().bytes()); + } + +} +/* +* ECDSA implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +ECDSA_Signature_Operation::ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa) : + base_point(ecdsa.domain().get_base_point()), + order(ecdsa.domain().get_order()), + x(ecdsa.private_value()), + mod_order(order) + { + } + +SecureVector +ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt m(msg, msg_len); + + BigInt r = 0, s = 0; + + while(r == 0 || s == 0) + { + // This contortion is necessary for the tests + BigInt k; + k.randomize(rng, order.bits()); + + while(k >= order) + k.randomize(rng, order.bits() - 1); + + PointGFp k_times_P = base_point * k; + r = mod_order.reduce(k_times_P.get_affine_x()); + s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m)); + } + + SecureVector output(2*order.bytes()); + r.binary_encode(&output[output.size() / 2 - r.bytes()]); + s.binary_encode(&output[output.size() - s.bytes()]); + return output; + } + +ECDSA_Verification_Operation::ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa) : + base_point(ecdsa.domain().get_base_point()), + public_point(ecdsa.public_point()), + order(ecdsa.domain().get_order()) + { + } + +bool ECDSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + if(sig_len != order.bytes()*2) + return false; + + BigInt e(msg, msg_len); + + BigInt r(sig, sig_len / 2); + BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= order || s <= 0 || s >= order) + return false; + + BigInt w = inverse_mod(s, order); + + PointGFp R = w * multi_exponentiate(base_point, e, + public_point, r); + + if(R.is_zero()) + return false; + + return (R.get_affine_x() % order == r); + } + +} +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* ElGamal_PublicKey Constructor +*/ +ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* ElGamal_PrivateKey Constructor +*/ +ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x.randomize(rng, 2 * dl_work_factor(group_p().bits())); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + y = power_mod(group_g(), x, group_p()); + load_check(rng); + } + +/* +* Check Private ElGamal Parameters +*/ +bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + return KeyPair::encryption_consistency_check(rng, *this, "EME1(SHA-1)"); + } + +ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key) + { + const BigInt& p = key.group_p(); + + powermod_g_p = Fixed_Base_Power_Mod(key.group_g(), p); + powermod_y_p = Fixed_Base_Power_Mod(key.get_y(), p); + mod_p = Modular_Reducer(p); + } + +SecureVector +ElGamal_Encryption_Operation::encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt& p = mod_p.get_modulus(); + + BigInt m(msg, msg_len); + + if(m >= p) + throw Invalid_Argument("ElGamal encryption: Input is too large"); + + BigInt k(rng, 2 * dl_work_factor(p.bits())); + + BigInt a = powermod_g_p(k); + BigInt b = mod_p.multiply(m, powermod_y_p(k)); + + SecureVector output(2*p.bytes()); + a.binary_encode(&output[p.bytes() - a.bytes()]); + b.binary_encode(&output[output.size() / 2 + (p.bytes() - b.bytes())]); + return output; + } + +ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key) + { + const BigInt& p = key.group_p(); + + powermod_x_p = Fixed_Exponent_Power_Mod(key.get_x(), p); + mod_p = Modular_Reducer(p); + + BigInt k(global_state().global_rng(), p.bits() - 1); + blinder = Blinder(k, powermod_x_p(k), p); + } + +SecureVector +ElGamal_Decryption_Operation::decrypt(const byte msg[], size_t msg_len) + { + const BigInt& p = mod_p.get_modulus(); + + const size_t p_bytes = p.bytes(); + + if(msg_len != 2 * p_bytes) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + BigInt a(msg, p_bytes); + BigInt b(msg + p_bytes, p_bytes); + + if(a >= p || b >= p) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + a = blinder.blind(a); + + BigInt r = mod_p.multiply(b, inverse_mod(powermod_x_p(a), p)); + + return BigInt::encode(blinder.unblind(r)); + } + +} +/* +* GOST 34.10-2001 implemenation +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +MemoryVector GOST_3410_PublicKey::x509_subject_public_key() const + { + // Trust CryptoPro to come up with something obnoxious + const BigInt x = public_point().get_affine_x(); + const BigInt y = public_point().get_affine_y(); + + size_t part_size = std::max(x.bytes(), y.bytes()); + + MemoryVector bits(2*part_size); + + x.binary_encode(&bits[part_size - x.bytes()]); + y.binary_encode(&bits[2*part_size - y.bytes()]); + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + return DER_Encoder().encode(bits, OCTET_STRING).get_contents(); + } + +AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const + { + MemoryVector params = + DER_Encoder().start_cons(SEQUENCE) + .encode(OID(domain().get_oid())) + .end_cons() + .get_contents(); + + return AlgorithmIdentifier(get_oid(), params); + } + +GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) + { + OID ecc_param_id; + + // Also includes hash and cipher OIDs... brilliant design guys + BER_Decoder(alg_id.parameters).start_cons(SEQUENCE).decode(ecc_param_id); + + domain_params = EC_Group(ecc_param_id); + + SecureVector bits; + BER_Decoder(key_bits).decode(bits, OCTET_STRING); + + const size_t part_size = bits.size() / 2; + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + BigInt x(&bits[0], part_size); + BigInt y(&bits[part_size], part_size); + + public_key = PointGFp(domain().get_curve(), x, y); + + BOTAN_ASSERT(public_key.on_the_curve(), + "Loaded GOST 34.10 public key not on the curve"); + } + +namespace { + +BigInt decode_le(const byte msg[], size_t msg_len) + { + SecureVector msg_le(msg, msg_len); + + for(size_t i = 0; i != msg_le.size() / 2; ++i) + std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); + + return BigInt(&msg_le[0], msg_le.size()); + } + +} + +GOST_3410_Signature_Operation::GOST_3410_Signature_Operation( + const GOST_3410_PrivateKey& gost_3410) : + + base_point(gost_3410.domain().get_base_point()), + order(gost_3410.domain().get_order()), + x(gost_3410.private_value()) + { + } + +SecureVector +GOST_3410_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + BigInt k; + do + k.randomize(rng, order.bits()-1); + while(k >= order); + + BigInt e = decode_le(msg, msg_len); + + e %= order; + if(e == 0) + e = 1; + + PointGFp k_times_P = base_point * k; + + BOTAN_ASSERT(k_times_P.on_the_curve(), + "GOST 34.10 k*g not on the curve"); + + BigInt r = k_times_P.get_affine_x() % order; + + BigInt s = (r*x + k*e) % order; + + if(r == 0 || s == 0) + throw Invalid_State("GOST 34.10: r == 0 || s == 0"); + + SecureVector output(2*order.bytes()); + s.binary_encode(&output[output.size() / 2 - s.bytes()]); + r.binary_encode(&output[output.size() - r.bytes()]); + return output; + } + +GOST_3410_Verification_Operation::GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost) : + base_point(gost.domain().get_base_point()), + public_point(gost.public_point()), + order(gost.domain().get_order()) + { + } + +bool GOST_3410_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + if(sig_len != order.bytes()*2) + return false; + + BigInt e = decode_le(msg, msg_len); + + BigInt s(sig, sig_len / 2); + BigInt r(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= order || s <= 0 || s >= order) + return false; + + e %= order; + if(e == 0) + e = 1; + + BigInt v = inverse_mod(e, order); + + BigInt z1 = (s*v) % order; + BigInt z2 = (-r*v) % order; + + PointGFp R = multi_exponentiate(base_point, z1, + public_point, z2); + + if(R.is_zero()) + return false; + + return (R.get_affine_x() == r); + } + +} +/* +* IF Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +AlgorithmIdentifier IF_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + +MemoryVector IF_Scheme_PublicKey::x509_subject_public_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(n) + .encode(e) + .end_cons() + .get_contents(); + } + +IF_Scheme_PublicKey::IF_Scheme_PublicKey(const AlgorithmIdentifier&, + const MemoryRegion& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(n) + .decode(e) + .verify_end() + .end_cons(); + } + +/* +* Check IF Scheme Public Parameters +*/ +bool IF_Scheme_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + if(n < 35 || n.is_even() || e < 2) + return false; + return true; + } + +MemoryVector IF_Scheme_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(0)) + .encode(n) + .encode(e) + .encode(d) + .encode(p) + .encode(q) + .encode(d1) + .encode(d2) + .encode(c) + .end_cons() + .get_contents(); + } + +IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const AlgorithmIdentifier&, + const MemoryRegion& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #1 key format version") + .decode(n) + .decode(e) + .decode(d) + .decode(p) + .decode(q) + .decode(d1) + .decode(d2) + .decode(c) + .end_cons(); + + load_check(rng); + } + +IF_Scheme_PrivateKey::IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, + const BigInt& prime2, + const BigInt& exp, + const BigInt& d_exp, + const BigInt& mod) + { + p = prime1; + q = prime2; + e = exp; + d = d_exp; + n = mod.is_nonzero() ? mod : p * q; + + if(d == 0) + { + BigInt inv_for_d = lcm(p - 1, q - 1); + if(e.is_even()) + inv_for_d >>= 1; + + d = inverse_mod(e, inv_for_d); + } + + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + load_check(rng); + } + +/* +* Check IF Scheme Private Parameters +*/ +bool IF_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(n < 35 || n.is_even() || e < 2 || d < 2 || p < 3 || q < 3 || p*q != n) + return false; + + if(!strong) + return true; + + if(d1 != d % (p - 1) || d2 != d % (q - 1) || c != inverse_mod(q, p)) + return false; + if(!check_prime(p, rng) || !check_prime(q, rng)) + return false; + return true; + } + +} +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace KeyPair { + +/* +* Check an encryption key pair for consistency +*/ +bool encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + PK_Encryptor_EME encryptor(key, padding); + PK_Decryptor_EME decryptor(key, padding); + + /* + Weird corner case, if the key is too small to encrypt anything at + all. This can happen with very small RSA keys with PSS + */ + if(encryptor.maximum_input_size() == 0) + return true; + + SecureVector plaintext = + rng.random_vec(encryptor.maximum_input_size() - 1); + + SecureVector ciphertext = encryptor.encrypt(plaintext, rng); + if(ciphertext == plaintext) + return false; + + SecureVector decrypted = decryptor.decrypt(ciphertext); + + return (plaintext == decrypted); + } + +/* +* Check a signature key pair for consistency +*/ +bool signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + PK_Signer signer(key, padding); + PK_Verifier verifier(key, padding); + + SecureVector message = rng.random_vec(16); + + SecureVector signature; + + try + { + signature = signer.sign_message(message, rng); + } + catch(Encoding_Error) + { + return false; + } + + if(!verifier.verify_message(message, signature)) + return false; + + // Now try to check a corrupt signature, ensure it does not succeed + ++message[0]; + + if(verifier.verify_message(message, signature)) + return false; + + return true; + } + +} + +} +/* +* Nyberg-Rueppel +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +NR_PublicKey::NR_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + +/* +* NR_PublicKey Constructor +*/ +NR_PublicKey::NR_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + } + +/* +* Create a NR private key +*/ +NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + x = BigInt::random_integer(rng, 2, group_q() - 1); + + y = power_mod(group_g(), x, group_p()); + + if(x_arg == 0) + gen_check(rng); + else + load_check(rng); + } + +NR_PrivateKey::NR_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + y = power_mod(group_g(), x, group_p()); + + load_check(rng); + } + +/* +* Check Private Nyberg-Rueppel Parameters +*/ +bool NR_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +NR_Signature_Operation::NR_Signature_Operation(const NR_PrivateKey& nr) : + q(nr.group_q()), + x(nr.get_x()), + powermod_g_p(nr.group_g(), nr.group_p()), + mod_q(nr.group_q()) + { + } + +SecureVector +NR_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + rng.add_entropy(msg, msg_len); + + BigInt f(msg, msg_len); + + if(f >= q) + throw Invalid_Argument("NR_Signature_Operation: Input is out of range"); + + BigInt c, d; + + while(c == 0) + { + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + c = mod_q.reduce(powermod_g_p(k) + f); + d = mod_q.reduce(k - x * c); + } + + SecureVector output(2*q.bytes()); + c.binary_encode(&output[output.size() / 2 - c.bytes()]); + d.binary_encode(&output[output.size() - d.bytes()]); + return output; + } + +NR_Verification_Operation::NR_Verification_Operation(const NR_PublicKey& nr) : + q(nr.group_q()), y(nr.get_y()) + { + powermod_g_p = Fixed_Base_Power_Mod(nr.group_g(), nr.group_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, nr.group_p()); + mod_p = Modular_Reducer(nr.group_p()); + mod_q = Modular_Reducer(nr.group_q()); + } + +SecureVector +NR_Verification_Operation::verify_mr(const byte msg[], size_t msg_len) + { + const BigInt& q = mod_q.get_modulus(); + + if(msg_len != 2*q.bytes()) + throw Invalid_Argument("NR verification: Invalid signature"); + + BigInt c(msg, q.bytes()); + BigInt d(msg + q.bytes(), q.bytes()); + + if(c.is_zero() || c >= q || d >= q) + throw Invalid_Argument("NR verification: Invalid signature"); + + BigInt i = mod_p.multiply(powermod_g_p(d), powermod_y_p(c)); + return BigInt::encode(mod_q.reduce(c - i)); + } + +} +/* +* PK Key +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_RSA) +#endif + +#if defined(BOTAN_HAS_DSA) +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +#endif + +#if defined(BOTAN_HAS_ECDSA) +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) +#endif + +#if defined(BOTAN_HAS_RW) +#endif + +#if defined(BOTAN_HAS_ELGAMAL) +#endif + +#if defined(BOTAN_HAS_ECDH) +#endif + +namespace Botan { + +Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) + { + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string()); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return new RSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") + return new RW_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return new DSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return new DH_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") + return new NR_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return new ElGamal_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return new ECDSA_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return new GOST_3410_PublicKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return new ECDH_PublicKey(alg_id, key_bits); +#endif + + return 0; + } + +Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) + { + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + alg_id.oid.as_string()); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return new RSA_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") + return new RW_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return new DSA_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return new DH_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") + return new NR_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return new ElGamal_PrivateKey(alg_id, key_bits, rng); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return new ECDSA_PrivateKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return new GOST_3410_PrivateKey(alg_id, key_bits); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return new ECDH_PrivateKey(alg_id, key_bits); +#endif + + return 0; + } + +} +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Default OID access +*/ +OID Public_Key::get_oid() const + { + try { + return OIDS::lookup(algo_name()); + } + catch(Lookup_Error) + { + throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); + } + } + +/* +* Run checks on a loaded public key +*/ +void Public_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid public key"); + } + +/* +* Run checks on a loaded private key +*/ +void Private_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid private key"); + } + +/* +* Run checks on a generated private key +*/ +void Private_Key::gen_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE)) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +} +/* +* PKCS #8 +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/* +* Get info from an EncryptedPrivateKeyInfo +*/ +SecureVector PKCS8_extract(DataSource& source, + AlgorithmIdentifier& pbe_alg_id) + { + SecureVector key_data; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(pbe_alg_id) + .decode(key_data, OCTET_STRING) + .verify_end(); + + return key_data; + } + +/* +* PEM decode and/or decrypt a private key +*/ +SecureVector PKCS8_decode(DataSource& source, const User_Interface& ui, + AlgorithmIdentifier& pk_alg_id) + { + AlgorithmIdentifier pbe_alg_id; + SecureVector key_data, key; + bool is_encrypted = true; + + try { + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + key_data = PKCS8_extract(source, pbe_alg_id); + else + { + std::string label; + key_data = PEM_Code::decode(source, label); + if(label == "PRIVATE KEY") + is_encrypted = false; + else if(label == "ENCRYPTED PRIVATE KEY") + { + DataSource_Memory key_source(key_data); + key_data = PKCS8_extract(key_source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error) + { + throw Decoding_Error("PKCS #8 private key decoding failed"); + } + + if(!is_encrypted) + key = key_data; + + const size_t MAX_TRIES = 3; + + size_t tries = 0; + while(true) + { + try { + if(MAX_TRIES && tries >= MAX_TRIES) + break; + + if(is_encrypted) + { + DataSource_Memory params(pbe_alg_id.parameters); + std::unique_ptr pbe(get_pbe(pbe_alg_id.oid, params)); + + User_Interface::UI_Result result = User_Interface::OK; + const std::string passphrase = + ui.get_passphrase("PKCS #8 private key", source.id(), result); + + if(result == User_Interface::CANCEL_ACTION) + break; + + pbe->set_key(passphrase); + Pipe decryptor(pbe.release()); + + decryptor.process_msg(key_data); + key = decryptor.read_all(); + } + + BER_Decoder(key) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #8 version number") + .decode(pk_alg_id) + .decode(key, OCTET_STRING) + .discard_remaining() + .end_cons(); + + break; + } + catch(Decoding_Error) + { + ++tries; + } + } + + if(key.empty()) + throw Decoding_Error("PKCS #8 private key decoding failed"); + return key; + } + +} + +/* +* BER encode a PKCS #8 private key, unencrypted +*/ +SecureVector BER_encode(const Private_Key& key) + { + const size_t PKCS8_VERSION = 0; + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(key.pkcs8_algorithm_identifier()) + .encode(key.pkcs8_private_key(), OCTET_STRING) + .end_cons() + .get_contents(); + } + +/* +* PEM encode a PKCS #8 private key, unencrypted +*/ +std::string PEM_encode(const Private_Key& key) + { + return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +SecureVector BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo) + { + const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)"; + + std::unique_ptr pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE))); + + pbe->new_params(rng); + pbe->set_key(pass); + + AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params()); + + Pipe key_encrytor(pbe.release()); + key_encrytor.process_msg(PKCS8::BER_encode(key)); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(pbe_algid) + .encode(key_encrytor.read_all(), OCTET_STRING) + .end_cons() + .get_contents(); + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo) + { + if(pass == "") + return PEM_encode(key); + + return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, pbe_algo), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const User_Interface& ui) + { + AlgorithmIdentifier alg_id; + SecureVector pkcs8_key = PKCS8_decode(source, ui, alg_id); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "" || alg_name == alg_id.oid.as_string()) + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + return make_private_key(alg_id, pkcs8_key, rng); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const User_Interface& ui) + { + DataSource_Stream source(fsname, true); + return PKCS8::load_key(source, rng, ui); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(source, rng, User_Interface(pass)); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(fsname, rng, User_Interface(pass)); + } + +/* +* Make a copy of this private key +*/ +Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng) + { + DataSource_Memory source(PEM_encode(key)); + return PKCS8::load_key(source, rng); + } + +} + +} +/* +* Public Key Base +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* PK_Encryptor_EME Constructor +*/ +PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, + const std::string& eme_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + op = engine->get_encryption_op(key); + if(op) + break; + } + + if(!op) + throw Lookup_Error("PK_Encryptor_EME: No working engine for " + + key.algo_name()); + + eme = (eme_name == "Raw") ? 0 : get_eme(eme_name); + } + +/* +* Encrypt a message +*/ +SecureVector +PK_Encryptor_EME::enc(const byte in[], + size_t length, + RandomNumberGenerator& rng) const + { + if(eme) + { + SecureVector encoded = + eme->encode(in, length, op->max_input_bits(), rng); + + if(8*(encoded.size() - 1) + high_bit(encoded[0]) > op->max_input_bits()) + throw Invalid_Argument("PK_Encryptor_EME: Input is too large"); + + return op->encrypt(&encoded[0], encoded.size(), rng); + } + else + { + if(8*(length - 1) + high_bit(in[0]) > op->max_input_bits()) + throw Invalid_Argument("PK_Encryptor_EME: Input is too large"); + + return op->encrypt(&in[0], length, rng); + } + } + +/* +* Return the max size, in bytes, of a message +*/ +size_t PK_Encryptor_EME::maximum_input_size() const + { + if(!eme) + return (op->max_input_bits() / 8); + else + return eme->maximum_input_size(op->max_input_bits()); + } + +/* +* PK_Decryptor_EME Constructor +*/ +PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, + const std::string& eme_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + op = engine->get_decryption_op(key); + if(op) + break; + } + + if(!op) + throw Lookup_Error("PK_Decryptor_EME: No working engine for " + + key.algo_name()); + + eme = (eme_name == "Raw") ? 0 : get_eme(eme_name); + } + +/* +* Decrypt a message +*/ +SecureVector PK_Decryptor_EME::dec(const byte msg[], + size_t length) const + { + try { + SecureVector decrypted = op->decrypt(msg, length); + if(eme) + return eme->decode(decrypted, op->max_input_bits()); + else + return decrypted; + } + catch(Invalid_Argument) + { + throw Decoding_Error("PK_Decryptor_EME: Input is invalid"); + } + } + +/* +* PK_Signer Constructor +*/ +PK_Signer::PK_Signer(const Private_Key& key, + const std::string& emsa_name, + Signature_Format format, + Fault_Protection prot) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + op = 0; + verify_op = 0; + + while(const Engine* engine = i.next()) + { + if(!op) + op = engine->get_signature_op(key); + + if(!verify_op && prot == ENABLE_FAULT_PROTECTION) + verify_op = engine->get_verify_op(key); + + if(op && (verify_op || prot == DISABLE_FAULT_PROTECTION)) + break; + } + + if(!op || (!verify_op && prot == ENABLE_FAULT_PROTECTION)) + throw Lookup_Error("PK_Signer: No working engine for " + + key.algo_name()); + + emsa = get_emsa(emsa_name); + sig_format = format; + } + +/* +* Sign a message +*/ +SecureVector PK_Signer::sign_message(const byte msg[], size_t length, + RandomNumberGenerator& rng) + { + update(msg, length); + return signature(rng); + } + +/* +* Add more to the message to be signed +*/ +void PK_Signer::update(const byte in[], size_t length) + { + emsa->update(in, length); + } + +/* +* Check the signature we just created, to help prevent fault attacks +*/ +bool PK_Signer::self_test_signature(const MemoryRegion& msg, + const MemoryRegion& sig) const + { + if(!verify_op) + return true; // checking disabled, assume ok + + if(verify_op->with_recovery()) + { + SecureVector recovered = + verify_op->verify_mr(&sig[0], sig.size()); + + if(msg.size() > recovered.size()) + { + size_t extra_0s = msg.size() - recovered.size(); + + for(size_t i = 0; i != extra_0s; ++i) + if(msg[i] != 0) + return false; + + return same_mem(&msg[extra_0s], &recovered[0], recovered.size()); + } + + return (recovered == msg); + } + else + return verify_op->verify(&msg[0], msg.size(), + &sig[0], sig.size()); + } + +/* +* Create a signature +*/ +SecureVector PK_Signer::signature(RandomNumberGenerator& rng) + { + SecureVector encoded = emsa->encoding_of(emsa->raw_data(), + op->max_input_bits(), + rng); + + SecureVector plain_sig = op->sign(&encoded[0], encoded.size(), rng); + + BOTAN_ASSERT(self_test_signature(encoded, plain_sig), + "PK_Signer consistency check failed"); + + if(op->message_parts() == 1 || sig_format == IEEE_1363) + return plain_sig; + + if(sig_format == DER_SEQUENCE) + { + if(plain_sig.size() % op->message_parts()) + throw Encoding_Error("PK_Signer: strange signature size found"); + const size_t SIZE_OF_PART = plain_sig.size() / op->message_parts(); + + std::vector sig_parts(op->message_parts()); + for(size_t j = 0; j != sig_parts.size(); ++j) + sig_parts[j].binary_decode(&plain_sig[SIZE_OF_PART*j], SIZE_OF_PART); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons() + .get_contents(); + } + else + throw Encoding_Error("PK_Signer: Unknown signature format " + + to_string(sig_format)); + } + +/* +* PK_Verifier Constructor +*/ +PK_Verifier::PK_Verifier(const Public_Key& key, + const std::string& emsa_name, + Signature_Format format) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + op = engine->get_verify_op(key); + if(op) + break; + } + + if(!op) + throw Lookup_Error("PK_Verifier: No working engine for " + + key.algo_name()); + + emsa = get_emsa(emsa_name); + sig_format = format; + } + +/* +* Set the signature format +*/ +void PK_Verifier::set_input_format(Signature_Format format) + { + if(op->message_parts() == 1 && format != IEEE_1363) + throw Invalid_State("PK_Verifier: This algorithm always uses IEEE 1363"); + sig_format = format; + } + +/* +* Verify a message +*/ +bool PK_Verifier::verify_message(const byte msg[], size_t msg_length, + const byte sig[], size_t sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +/* +* Append to the message +*/ +void PK_Verifier::update(const byte in[], size_t length) + { + emsa->update(in, length); + } + +/* +* Check a signature +*/ +bool PK_Verifier::check_signature(const byte sig[], size_t length) + { + try { + if(sig_format == IEEE_1363) + return validate_signature(emsa->raw_data(), sig, length); + else if(sig_format == DER_SEQUENCE) + { + BER_Decoder decoder(sig, length); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); + + size_t count = 0; + SecureVector real_sig; + while(ber_sig.more_items()) + { + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig += BigInt::encode_1363(sig_part, op->message_part_size()); + ++count; + } + + if(count != op->message_parts()) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + return validate_signature(emsa->raw_data(), + &real_sig[0], real_sig.size()); + } + else + throw Decoding_Error("PK_Verifier: Unknown signature format " + + to_string(sig_format)); + } + catch(Invalid_Argument) { return false; } + } + +/* +* Verify a signature +*/ +bool PK_Verifier::validate_signature(const MemoryRegion& msg, + const byte sig[], size_t sig_len) + { + if(op->with_recovery()) + { + SecureVector output_of_key = op->verify_mr(sig, sig_len); + return emsa->verify(output_of_key, msg, op->max_input_bits()); + } + else + { + Null_RNG rng; + + SecureVector encoded = + emsa->encoding_of(msg, op->max_input_bits(), rng); + + return op->verify(&encoded[0], encoded.size(), sig, sig_len); + } + } + +/* +* PK_Key_Agreement Constructor +*/ +PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& key, + const std::string& kdf_name) + { + Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory()); + + while(const Engine* engine = i.next()) + { + op = engine->get_key_agreement_op(key); + if(op) + break; + } + + if(!op) + throw Lookup_Error("PK_Key_Agreement: No working engine for " + + key.algo_name()); + + kdf = (kdf_name == "Raw") ? 0 : get_kdf(kdf_name); + } + +SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, const byte in[], + size_t in_len, const byte params[], + size_t params_len) const + { + SecureVector z = op->agree(in, in_len); + + if(!kdf) + return z; + + return kdf->derive_key(key_len, z, params, params_len); + } + +} +/* +* KeyUsage +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace BER { + +/* +* Decode a BER encoded KeyUsage +*/ +void decode(BER_Decoder& source, Key_Constraints& key_usage) + { + BER_Object obj = source.get_next_object(); + + if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Bad tag for usage constraint", + obj.type_tag, obj.class_tag); + if(obj.value.size() != 2 && obj.value.size() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + const byte mask = (0xFF << obj.value[0]); + obj.value[obj.value.size()-1] &= mask; + + u16bit usage = 0; + for(size_t j = 1; j != obj.value.size(); ++j) + usage = (obj.value[j] << 8) | usage; + + key_usage = Key_Constraints(usage); + } + +} + +} +/* +* RSA +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Create a RSA private key +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 512) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + + do + { + p = random_prime(rng, (bits + 1) / 2, e); + q = random_prime(rng, bits - p.bits(), e); + n = p * q; + } while(n.bits() != bits); + + d = inverse_mod(e, lcm(p - 1, q - 1)); + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + gen_check(rng); + } + +/* +* Check Private RSA Parameters +*/ +bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % lcm(p - 1, q - 1) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-1)"); + } + +RSA_Private_Operation::RSA_Private_Operation(const RSA_PrivateKey& rsa) : + n(rsa.get_n()), + q(rsa.get_q()), + c(rsa.get_c()), + powermod_e_n(rsa.get_e(), rsa.get_n()), + powermod_d1_p(rsa.get_d1(), rsa.get_p()), + powermod_d2_q(rsa.get_d2(), rsa.get_q()), + mod_p(rsa.get_p()) + { + BigInt k(global_state().global_rng(), n.bits() - 1); + blinder = Blinder(powermod_e_n(k), inverse_mod(k, n), n); + } + +BigInt RSA_Private_Operation::private_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA private op - input is too large"); + + BigInt j1 = powermod_d1_p(m); + BigInt j2 = powermod_d2_q(m); + + j1 = mod_p.reduce(sub_mul(j1, j2, c)); + + return mul_add(j1, q, j2); + } + +SecureVector +RSA_Private_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + /* We don't check signatures against powermod_e_n here because + PK_Signer checks verification consistency for all signature + algorithms. + */ + + BigInt m(msg, msg_len); + BigInt x = blinder.unblind(private_op(blinder.blind(m))); + return BigInt::encode_1363(x, n.bytes()); + } + +/* +* RSA Decryption Operation +*/ +SecureVector +RSA_Private_Operation::decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + BigInt x = blinder.unblind(private_op(blinder.blind(m))); + + BOTAN_ASSERT(m == powermod_e_n(x), + "RSA private op failed consistency check"); + + return BigInt::encode(x); + } + +} +/* +* Rabin-Williams +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Create a Rabin-Williams private key +*/ +RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 512) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + to_string(bits) + " bits long"); + if(exp < 2 || exp % 2 == 1) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + + do + { + p = random_prime(rng, (bits + 1) / 2, e / 2, 3, 4); + q = random_prime(rng, bits - p.bits(), e / 2, ((p % 8 == 3) ? 7 : 3), 8); + n = p * q; + } while(n.bits() != bits); + + d = inverse_mod(e, lcm(p - 1, q - 1) >> 1); + d1 = d % (p - 1); + d2 = d % (q - 1); + c = inverse_mod(q, p); + + gen_check(rng); + } + +/* +* Check Private Rabin-Williams Parameters +*/ +bool RW_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % (lcm(p - 1, q - 1) / 2) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA2(SHA-1)"); + } + +RW_Signature_Operation::RW_Signature_Operation(const RW_PrivateKey& rw) : + n(rw.get_n()), + e(rw.get_e()), + q(rw.get_q()), + c(rw.get_c()), + powermod_d1_p(rw.get_d1(), rw.get_p()), + powermod_d2_q(rw.get_d2(), rw.get_q()), + mod_p(rw.get_p()) + { + } + +SecureVector +RW_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + if(!blinder.initialized()) + { + BigInt k(rng, n.bits() / 2); + blinder = Blinder(power_mod(k, e, n), inverse_mod(k, n), n); + } + + BigInt i(msg, msg_len); + + if(i >= n || i % 16 != 12) + throw Invalid_Argument("Rabin-Williams: invalid input"); + + if(jacobi(i, n) != 1) + i >>= 1; + + i = blinder.blind(i); + + BigInt j1 = powermod_d1_p(i); + BigInt j2 = powermod_d2_q(i); + j1 = mod_p.reduce(sub_mul(j1, j2, c)); + + BigInt r = blinder.unblind(mul_add(j1, q, j2)); + + r = std::min(r, n - r); + + return BigInt::encode_1363(r, n.bytes()); + } + +SecureVector +RW_Verification_Operation::verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + + if((m > (n >> 1)) || m.is_negative()) + throw Invalid_Argument("RW signature verification: m > n / 2 || m < 0"); + + BigInt r = powermod_e_n(m); + if(r % 16 == 12) + return BigInt::encode(r); + if(r % 8 == 6) + return BigInt::encode(2*r); + + r = n - r; + if(r % 16 == 12) + return BigInt::encode(r); + if(r % 8 == 6) + return BigInt::encode(2*r); + + throw Invalid_Argument("RW signature verification: Invalid signature"); + } + +} +/* +* Public Key Work Factor Functions +* (C) 1999-2007,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +size_t dl_work_factor(size_t bits) + { + /* + Based on GNFS work factors. Constant is 1.43 times the asymptotic + value; I'm not sure but I believe that came from a paper on 'real + world' runtimes, but I don't remember where now. + + Sample return values: + |512| -> 64 + |1024| -> 86 + |1536| -> 102 + |2048| -> 116 + |3072| -> 138 + |4096| -> 155 + |8192| -> 206 + + For DL algos, we use an exponent of twice the size of the result; + the assumption is that an arbitrary discrete log on a group of size + bits would take about 2^n effort, and thus using an exponent of + size 2^(2*n) implies that all available attacks are about as easy + (as e.g Pollard's kangaroo algorithm can compute the DL in sqrt(x) + operations) while minimizing the exponent size for performance + reasons. + */ + + const size_t MIN_WORKFACTOR = 64; + + // approximates natural logarithm of p + const double log_p = bits / 1.4426; + + const double strength = + 2.76 * std::pow(log_p, 1.0/3.0) * std::pow(std::log(log_p), 2.0/3.0); + + return std::max(static_cast(strength), MIN_WORKFACTOR); + } + +} +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace X509 { + +MemoryVector BER_encode(const Public_Key& key) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(key.algorithm_identifier()) + .encode(key.x509_subject_public_key(), BIT_STRING) + .end_cons() + .get_contents(); + } + +/* +* PEM encode a X.509 public key +*/ +std::string PEM_encode(const Public_Key& key) + { + return PEM_Code::encode(X509::BER_encode(key), + "PUBLIC KEY"); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + MemoryVector key_bits; + + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + + if(key_bits.empty()) + throw Decoding_Error("X.509 public key decoding failed"); + + return make_public_key(alg_id, key_bits); + } + catch(Decoding_Error) + { + throw Decoding_Error("X.509 public key decoding failed"); + } + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname, true); + return X509::load_key(source); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const MemoryRegion& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/* +* Make a copy of this public key +*/ +Public_Key* copy_key(const Public_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return X509::load_key(source); + } + +/* +* Find the allowable key constraints +*/ +Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits) + { + const std::string name = pub_key.algo_name(); + + size_t constraints = 0; + + if(name == "DH" || name == "ECDH") + constraints |= KEY_AGREEMENT; + + if(name == "RSA" || name == "ElGamal") + constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; + + if(name == "RSA" || name == "RW" || name == "NR" || + name == "DSA" || name == "ECDSA") + constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION; + + if(limits) + constraints &= limits; + + return Key_Constraints(constraints); + } + +} + +} +/* +* HMAC_RNG +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +void hmac_prf(MessageAuthenticationCode* prf, + MemoryRegion& K, + u32bit& counter, + const std::string& label) + { + prf->update(K); + prf->update(label); + prf->update_be(counter); + prf->final(&K[0]); + + ++counter; + } + +} + +/* +* Generate a buffer of random bytes +*/ +void HMAC_RNG::randomize(byte out[], size_t length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + /* + HMAC KDF as described in E-t-E, using a CTXinfo of "rng" + */ + while(length) + { + hmac_prf(prf, K, counter, "rng"); + + const size_t copied = std::min(K.size(), length); + + copy_mem(out, &K[0], copied); + out += copied; + length -= copied; + } + } + +/* +* Poll for entropy and reset the internal keys +*/ +void HMAC_RNG::reseed(size_t poll_bits) + { + /* + Using the terminology of E-t-E, XTR is the MAC function (normally + HMAC) seeded with XTS (below) and we form SKM, the key material, by + fast polling each source, and then slow polling as many as we think + we need (in the following loop), and feeding all of the poll + results, along with any optional user input, along with, finally, + feedback of the current PRK value, into the extractor function. + */ + + Entropy_Accumulator_BufferedComputation accum(*extractor, poll_bits); + + if(!entropy_sources.empty()) + { + size_t poll_attempt = 0; + + while(!accum.polling_goal_achieved() && poll_attempt < poll_bits) + { + const size_t src_idx = poll_attempt % entropy_sources.size(); + entropy_sources[src_idx]->poll(accum); + ++poll_attempt; + } + } + + /* + * It is necessary to feed forward poll data. Otherwise, a good poll + * (collecting a large amount of conditional entropy) followed by a + * bad one (collecting little) would be unsafe. Do this by + * generating new PRF outputs using the previous key and feeding + * them into the extractor function. + * + * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF + * output using the CTXinfo "reseed". Provide these values as input + * to the extractor function. + */ + hmac_prf(prf, K, counter, "rng"); + extractor->update(K); // K is the CTXinfo=rng PRF output + + hmac_prf(prf, K, counter, "reseed"); + extractor->update(K); // K is the CTXinfo=reseed PRF output + + /* Now derive the new PRK using everything that has been fed into + the extractor, and set the PRF key to that */ + prf->set_key(extractor->final()); + + // Now generate a new PRF output to use as the XTS extractor salt + hmac_prf(prf, K, counter, "xts"); + extractor->set_key(K); + + // Reset state + zeroise(K); + counter = 0; + user_input_len = 0; + + /* + Consider ourselves seeded once we've collected an estimated 128 bits of + entropy in a single poll. + */ + if(seeded == false && accum.bits_collected() >= 128) + seeded = true; + } + +/* +* Add user-supplied entropy to the extractor input +*/ +void HMAC_RNG::add_entropy(const byte input[], size_t length) + { + const size_t USER_ENTROPY_WATERSHED = 64; + + extractor->update(input, length); + user_input_len += length; + + /* + * After we've accumulated at least USER_ENTROPY_WATERSHED bytes of + * user input, reseed. This input will automatically have been + * included if reseed was called already, as it's just included in + * the extractor input. + */ + if(user_input_len >= USER_ENTROPY_WATERSHED) + reseed(0); + } + +/* +* Add another entropy source to the list +*/ +void HMAC_RNG::add_entropy_source(EntropySource* src) + { + entropy_sources.push_back(src); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC_RNG::clear() + { + extractor->clear(); + prf->clear(); + zeroise(K); + counter = 0; + user_input_len = 0; + seeded = false; + } + +/* +* Return the name of this type +*/ +std::string HMAC_RNG::name() const + { + return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")"; + } + +/* +* HMAC_RNG Constructor +*/ +HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, + MessageAuthenticationCode* prf_mac) : + extractor(extractor_mac), prf(prf_mac) + { + if(!prf->valid_keylength(extractor->output_length()) || + !extractor->valid_keylength(prf->output_length())) + throw Invalid_Argument("HMAC_RNG: Bad algo combination " + + extractor->name() + " and " + + prf->name()); + + // First PRF inputs are all zero, as specified in section 2 + K.resize(prf->output_length()); + + counter = 0; + user_input_len = 0; + seeded = false; + + /* + Normally we want to feedback PRF output into the input to the + extractor function to ensure a single bad poll does not damage the + RNG, but obviously that is meaningless to do on the first poll. + + We will want to use the PRF before we set the first key (in + reseed), and it is a pain to keep track if it is set or + not. Since the first time it doesn't matter anyway, just set the + PRF key to constant zero: randomize() will not produce output + unless is_seeded() returns true, and that will only be the case if + the estimated entropy counter is high enough. That variable is only + set when a reseeding is performed. + */ + MemoryVector prf_key(extractor->output_length()); + prf->set_key(prf_key); + + /* + Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key. + + This will be used during the first extraction sequence; XTS values + after this one are generated using the PRF. + + If I understand the E-t-E paper correctly (specifically Section 4), + using this fixed extractor key is safe to do. + */ + extractor->set_key(prf->process("Botan HMAC_RNG XTS")); + } + +/* +* HMAC_RNG Destructor +*/ +HMAC_RNG::~HMAC_RNG() + { + delete extractor; + delete prf; + + std::for_each(entropy_sources.begin(), entropy_sources.end(), + del_fun()); + + counter = 0; + } + +} +/* +* Randpool +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace { + +/* +* PRF based on a MAC +*/ +enum RANDPOOL_PRF_TAG { + CIPHER_KEY = 0, + MAC_KEY = 1, + GEN_OUTPUT = 2 +}; + +} + +/* +* Generate a buffer of random bytes +*/ +void Randpool::randomize(byte out[], size_t length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + update_buffer(); + while(length) + { + const size_t copied = std::min(length, buffer.size()); + copy_mem(out, &buffer[0], copied); + out += copied; + length -= copied; + update_buffer(); + } + } + +/* +* Refill the output buffer +*/ +void Randpool::update_buffer() + { + for(size_t i = 0; i != counter.size(); ++i) + if(++counter[i]) + break; + + mac->update(static_cast(GEN_OUTPUT)); + mac->update(counter); + SecureVector mac_val = mac->final(); + + for(size_t i = 0; i != mac_val.size(); ++i) + buffer[i % buffer.size()] ^= mac_val[i]; + cipher->encrypt(buffer); + + if(counter[0] % ITERATIONS_BEFORE_RESEED == 0) + mix_pool(); + } + +/* +* Mix the entropy pool +*/ +void Randpool::mix_pool() + { + const size_t BLOCK_SIZE = cipher->block_size(); + + mac->update(static_cast(MAC_KEY)); + mac->update(pool); + mac->set_key(mac->final()); + + mac->update(static_cast(CIPHER_KEY)); + mac->update(pool); + cipher->set_key(mac->final()); + + xor_buf(pool, buffer, BLOCK_SIZE); + cipher->encrypt(pool); + for(size_t i = 1; i != POOL_BLOCKS; ++i) + { + const byte* previous_block = &pool[BLOCK_SIZE*(i-1)]; + byte* this_block = &pool[BLOCK_SIZE*i]; + xor_buf(this_block, previous_block, BLOCK_SIZE); + cipher->encrypt(this_block); + } + + update_buffer(); + } + +/* +* Reseed the internal state +*/ +void Randpool::reseed(size_t poll_bits) + { + Entropy_Accumulator_BufferedComputation accum(*mac, poll_bits); + + if(!entropy_sources.empty()) + { + size_t poll_attempt = 0; + + while(!accum.polling_goal_achieved() && poll_attempt < poll_bits) + { + entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum); + ++poll_attempt; + } + } + + SecureVector mac_val = mac->final(); + + xor_buf(pool, mac_val, mac_val.size()); + mix_pool(); + + if(accum.bits_collected() >= poll_bits) + seeded = true; + } + +/* +* Add user-supplied entropy +*/ +void Randpool::add_entropy(const byte input[], size_t length) + { + SecureVector mac_val = mac->process(input, length); + xor_buf(pool, mac_val, mac_val.size()); + mix_pool(); + + if(length) + seeded = true; + } + +/* +* Add another entropy source to the list +*/ +void Randpool::add_entropy_source(EntropySource* src) + { + entropy_sources.push_back(src); + } + +/* +* Clear memory of sensitive data +*/ +void Randpool::clear() + { + cipher->clear(); + mac->clear(); + zeroise(pool); + zeroise(buffer); + zeroise(counter); + seeded = false; + } + +/* +* Return the name of this type +*/ +std::string Randpool::name() const + { + return "Randpool(" + cipher->name() + "," + mac->name() + ")"; + } + +/* +* Randpool Constructor +*/ +Randpool::Randpool(BlockCipher* cipher_in, + MessageAuthenticationCode* mac_in, + size_t pool_blocks, + size_t iter_before_reseed) : + ITERATIONS_BEFORE_RESEED(iter_before_reseed), + POOL_BLOCKS(pool_blocks), + cipher(cipher_in), + mac(mac_in) + { + const size_t BLOCK_SIZE = cipher->block_size(); + const size_t OUTPUT_LENGTH = mac->output_length(); + + if(OUTPUT_LENGTH < BLOCK_SIZE || + !cipher->valid_keylength(OUTPUT_LENGTH) || + !mac->valid_keylength(OUTPUT_LENGTH)) + { + const std::string cipherName = cipher->name(); + const std::string macName = mac->name(); + delete cipher; + delete mac; + throw Internal_Error("Randpool: Invalid algorithm combination " + + cipherName + "/" + macName); + } + + buffer.resize(BLOCK_SIZE); + pool.resize(POOL_BLOCKS * BLOCK_SIZE); + counter.resize(12); + seeded = false; + } + +/* +* Randpool Destructor +*/ +Randpool::~Randpool() + { + delete cipher; + delete mac; + + std::for_each(entropy_sources.begin(), entropy_sources.end(), + del_fun()); + } + +} +/* +* Random Number Generator Base +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) +#endif + +namespace Botan { + +/* +* Get a single random byte +*/ +byte RandomNumberGenerator::next_byte() + { + byte out; + this->randomize(&out, 1); + return out; + } + +/* +* Create and seed a new RNG object +*/ +RandomNumberGenerator* RandomNumberGenerator::make_rng() + { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + return new AutoSeeded_RNG; +#endif + + throw Algorithm_Not_Found("RandomNumberGenerator::make_rng - no RNG found"); + } + +} +/* +* ANSI X9.31 RNG +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* Generate a buffer of random bytes +*/ +void ANSI_X931_RNG::randomize(byte out[], size_t length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + while(length) + { + if(position == R.size()) + update_buffer(); + + const size_t copied = std::min(length, R.size() - position); + + copy_mem(out, &R[position], copied); + out += copied; + length -= copied; + position += copied; + } + } + +/* +* Refill the internal state +*/ +void ANSI_X931_RNG::update_buffer() + { + const size_t BLOCK_SIZE = cipher->block_size(); + + SecureVector DT = prng->random_vec(BLOCK_SIZE); + cipher->encrypt(DT); + + xor_buf(&R[0], &V[0], &DT[0], BLOCK_SIZE); + cipher->encrypt(R); + + xor_buf(&V[0], &R[0], &DT[0], BLOCK_SIZE); + cipher->encrypt(V); + + position = 0; + } + +/* +* Reset V and the cipher key with new values +*/ +void ANSI_X931_RNG::rekey() + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(prng->is_seeded()) + { + cipher->set_key(prng->random_vec(cipher->maximum_keylength())); + + if(V.size() != BLOCK_SIZE) + V.resize(BLOCK_SIZE); + prng->randomize(&V[0], V.size()); + + update_buffer(); + } + } + +/* +* Reseed the internal state +*/ +void ANSI_X931_RNG::reseed(size_t poll_bits) + { + prng->reseed(poll_bits); + rekey(); + } + +/* +* Add a entropy source to the underlying PRNG +*/ +void ANSI_X931_RNG::add_entropy_source(EntropySource* src) + { + prng->add_entropy_source(src); + } + +/* +* Add some entropy to the underlying PRNG +*/ +void ANSI_X931_RNG::add_entropy(const byte input[], size_t length) + { + prng->add_entropy(input, length); + rekey(); + } + +/* +* Check if the PRNG is seeded +*/ +bool ANSI_X931_RNG::is_seeded() const + { + return (V.size() > 0); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X931_RNG::clear() + { + cipher->clear(); + prng->clear(); + zeroise(R); + V.clear(); + + position = 0; + } + +/* +* Return the name of this type +*/ +std::string ANSI_X931_RNG::name() const + { + return "X9.31(" + cipher->name() + ")"; + } + +/* +* ANSI X931 RNG Constructor +*/ +ANSI_X931_RNG::ANSI_X931_RNG(BlockCipher* cipher_in, + RandomNumberGenerator* prng_in) + { + if(!prng_in || !cipher_in) + throw Invalid_Argument("ANSI_X931_RNG constructor: NULL arguments"); + + cipher = cipher_in; + prng = prng_in; + + R.resize(cipher->block_size()); + position = 0; + } + +/* +* ANSI X931 RNG Destructor +*/ +ANSI_X931_RNG::~ANSI_X931_RNG() + { + delete cipher; + delete prng; + } + +} +/* +* Startup Self Tests +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Perform a Known Answer Test +*/ +bool test_filter_kat(Filter* filter, + const std::string& input, + const std::string& expected_output) + { + Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder); + pipe.process_msg(input); + + const std::string output = pipe.read_all_as_string(); + + return (output == expected_output); + } + +} + +/* +* Run a set of KATs +*/ +std::map +algorithm_kat(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af) + { + const std::string& algo = algo_name.algo_name_and_args(); + + std::vector providers = af.providers_of(algo); + std::map all_results; + + if(providers.empty()) // no providers, nothing to do + return all_results; + + const std::string input = search_map(vars, std::string("input")); + const std::string output = search_map(vars, std::string("output")); + + SymmetricKey key(search_map(vars, std::string("key"))); + InitializationVector iv(search_map(vars, std::string("iv"))); + + for(size_t i = 0; i != providers.size(); ++i) + { + const std::string provider = providers[i]; + + if(const HashFunction* proto = + af.prototype_hash_function(algo, provider)) + { + Filter* filt = new Hash_Filter(proto->clone()); + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const MessageAuthenticationCode* proto = + af.prototype_mac(algo, provider)) + { + Keyed_Filter* filt = new MAC_Filter(proto->clone(), key); + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const StreamCipher* proto = + af.prototype_stream_cipher(algo, provider)) + { + Keyed_Filter* filt = new StreamCipher_Filter(proto->clone()); + filt->set_key(key); + filt->set_iv(iv); + + all_results[provider] = test_filter_kat(filt, input, output); + } + else if(const BlockCipher* proto = + af.prototype_block_cipher(algo, provider)) + { + Keyed_Filter* enc = get_cipher_mode(proto, ENCRYPTION, + algo_name.cipher_mode(), + algo_name.cipher_mode_pad()); + + Keyed_Filter* dec = get_cipher_mode(proto, DECRYPTION, + algo_name.cipher_mode(), + algo_name.cipher_mode_pad()); + + if(!enc || !dec) + { + delete enc; + delete dec; + continue; + } + + enc->set_key(key); + + if(enc->valid_iv_length(iv.length())) + enc->set_iv(iv); + else if(!enc->valid_iv_length(0)) + throw Invalid_IV_Length(algo, iv.length()); + + dec->set_key(key); + + if(dec->valid_iv_length(iv.length())) + dec->set_iv(iv); + else if(!dec->valid_iv_length(0)) + throw Invalid_IV_Length(algo, iv.length()); + + bool enc_ok = test_filter_kat(enc, input, output); + bool dec_ok = test_filter_kat(dec, output, input); + + all_results[provider] = enc_ok && dec_ok; + } + } + + return all_results; + } + +namespace { + +void verify_results(const std::string& algo, + const std::map& results) + { + for(std::map::const_iterator i = results.begin(); + i != results.end(); ++i) + { + if(!i->second) + throw Self_Test_Failure(algo + " self-test failed, provider "+ + i->first); + } + } + +void hash_test(Algorithm_Factory& af, + const std::string& name, + const std::string& in, + const std::string& out) + { + std::map vars; + vars["input"] = in; + vars["output"] = out; + + verify_results(name, algorithm_kat(name, vars, af)); + } + +void mac_test(Algorithm_Factory& af, + const std::string& name, + const std::string& in, + const std::string& out, + const std::string& key) + { + std::map vars; + vars["input"] = in; + vars["output"] = out; + vars["key"] = key; + + verify_results(name, algorithm_kat(name, vars, af)); + } + +/* +* Perform a KAT for a cipher +*/ +void cipher_kat(Algorithm_Factory& af, + const std::string& algo, + const std::string& key_str, + const std::string& iv_str, + const std::string& in, + const std::string& ecb_out, + const std::string& cbc_out, + const std::string& cfb_out, + const std::string& ofb_out, + const std::string& ctr_out) + { + SymmetricKey key(key_str); + InitializationVector iv(iv_str); + + std::map vars; + vars["key"] = key_str; + vars["iv"] = iv_str; + vars["input"] = in; + + std::map results; + + vars["output"] = ecb_out; + verify_results(algo + "/ECB", algorithm_kat(algo + "/ECB", vars, af)); + + vars["output"] = cbc_out; + verify_results(algo + "/CBC", + algorithm_kat(algo + "/CBC/NoPadding", vars, af)); + + vars["output"] = cfb_out; + verify_results(algo + "/CFB", algorithm_kat(algo + "/CFB", vars, af)); + + vars["output"] = ofb_out; + verify_results(algo + "/OFB", algorithm_kat(algo + "/OFB", vars, af)); + + vars["output"] = ctr_out; + verify_results(algo + "/CTR", algorithm_kat(algo + "/CTR-BE", vars, af)); + } + +} + +/* +* Perform Self Tests +*/ +bool passes_self_tests(Algorithm_Factory& af) + { + try + { + confirm_startup_self_tests(af); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +/* +* Perform Self Tests +*/ +void confirm_startup_self_tests(Algorithm_Factory& af) + { + cipher_kat(af, "DES", + "0123456789ABCDEF", "1234567890ABCDEF", + "4E6F77206973207468652074696D6520666F7220616C6C20", + "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53", + "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6", + "F3096249C7F46E51A69E839B1A92F78403467133898EA622", + "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3", + "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75"); + + cipher_kat(af, "TripleDES", + "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E", + "C141B5FCCD28DC8A", + "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68", + "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4", + "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9", + "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B", + "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62", + "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371"); + + cipher_kat(af, "AES-128", + "2B7E151628AED2A6ABF7158809CF4F3C", + "000102030405060708090A0B0C0D0E0F", + "6BC1BEE22E409F96E93D7E117393172A" + "AE2D8A571E03AC9C9EB76FAC45AF8E51", + "3AD77BB40D7A3660A89ECAF32466EF97" + "F5D3D58503B9699DE785895A96FDBAAF", + "7649ABAC8119B246CEE98E9B12E9197D" + "5086CB9B507219EE95DB113A917678B2", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "C8A64537A0B3A93FCDE3CDAD9F1CE58B", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "7789508D16918F03F53C52DAC54ED825", + "3B3FD92EB72DAD20333449F8E83CFB4A" + "010C041999E03F36448624483E582D0E"); + + hash_test(af, "SHA-1", + "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); + + hash_test(af, "SHA-1", + "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + hash_test(af, "SHA-1", + "6162636462636465636465666465666765666768666768696768696A" + "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071", + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"); + + mac_test(af, "HMAC(SHA-1)", + "4869205468657265", + "B617318655057264E28BC0B6FB378C8EF146BE00", + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"); + + hash_test(af, "SHA-256", + "", + "E3B0C44298FC1C149AFBF4C8996FB924" + "27AE41E4649B934CA495991B7852B855"); + + hash_test(af, "SHA-256", + "616263", + "BA7816BF8F01CFEA414140DE5DAE2223" + "B00361A396177A9CB410FF61F20015AD"); + + hash_test(af, "SHA-256", + "6162636462636465636465666465666765666768666768696768696A" + "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071", + "248D6A61D20638B8E5C026930C3E6039" + "A33CE45964FF2167F6ECEDD419DB06C1"); + + mac_test(af, "HMAC(SHA-256)", + "4869205468657265", + "198A607EB44BFBC69903A0F1CF2BBDC5" + "BA0AA3F3D9AE3C1C7A3B1696A0B68CF7", + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B" + "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"); + } + +} +/* +* ARC4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Combine cipher stream with message +*/ +void ARC4::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + generate(); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Generate cipher stream +*/ +void ARC4::generate() + { + byte SX, SY; + for(size_t i = 0; i != buffer.size(); i += 4) + { + SX = state[X+1]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+1] = SY; state[Y] = SX; + buffer[i] = state[(SX + SY) % 256]; + + SX = state[X+2]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+2] = SY; state[Y] = SX; + buffer[i+1] = state[(SX + SY) % 256]; + + SX = state[X+3]; Y = (Y + SX) % 256; SY = state[Y]; + state[X+3] = SY; state[Y] = SX; + buffer[i+2] = state[(SX + SY) % 256]; + + X = (X + 4) % 256; + SX = state[X]; Y = (Y + SX) % 256; SY = state[Y]; + state[X] = SY; state[Y] = SX; + buffer[i+3] = state[(SX + SY) % 256]; + } + position = 0; + } + +/* +* ARC4 Key Schedule +*/ +void ARC4::key_schedule(const byte key[], size_t length) + { + clear(); + + for(size_t i = 0; i != 256; ++i) + state[i] = static_cast(i); + + for(size_t i = 0, state_index = 0; i != 256; ++i) + { + state_index = (state_index + key[i % length] + state[i]) % 256; + std::swap(state[i], state[state_index]); + } + + for(size_t i = 0; i <= SKIP; i += buffer.size()) + generate(); + + position += (SKIP % buffer.size()); + } + +/* +* Return the name of this type +*/ +std::string ARC4::name() const + { + if(SKIP == 0) return "ARC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + to_string(SKIP) + ")"; + } + +/* +* Clear memory of sensitive data +*/ +void ARC4::clear() + { + zeroise(state); + zeroise(buffer); + position = X = Y = 0; + } + +/* +* ARC4 Constructor +*/ +ARC4::ARC4(size_t s) : SKIP(s), + state(256), + buffer(DEFAULT_BUFFERSIZE) + { + clear(); + } + +} +/* +* Counter mode +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* CTR-BE Constructor +*/ + +CTR_BE::CTR_BE(BlockCipher* ciph) : + permutation(ciph), + counter(256 * permutation->block_size()), + buffer(counter.size()), + position(0) + { + } + +/* +* CTR_BE Destructor +*/ +CTR_BE::~CTR_BE() + { + delete permutation; + } + +/* +* Zeroize +*/ +void CTR_BE::clear() + { + permutation->clear(); + zeroise(buffer); + zeroise(counter); + position = 0; + } + +/* +* Set the key +*/ +void CTR_BE::key_schedule(const byte key[], size_t key_len) + { + permutation->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(0, 0); + } + +/* +* Return the name of this type +*/ +std::string CTR_BE::name() const + { + return ("CTR-BE(" + permutation->name() + ")"); + } + +/* +* CTR-BE Encryption/Decryption +*/ +void CTR_BE::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + increment_counter(); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Set CTR-BE IV +*/ +void CTR_BE::set_iv(const byte iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + const size_t bs = permutation->block_size(); + + zeroise(counter); + + counter.copy(0, iv, iv_len); + + /* + * Set counter blocks to IV, IV + 1, ... IV + 255 + */ + for(size_t i = 1; i != 256; ++i) + { + counter.copy(i*bs, &counter[(i-1)*bs], bs); + + for(size_t j = 0; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) + break; + } + + permutation->encrypt_n(&counter[0], &buffer[0], 256); + position = 0; + } + +/* +* Increment the counter and update the buffer +*/ +void CTR_BE::increment_counter() + { + const size_t bs = permutation->block_size(); + + /* + * Each counter value always needs to be incremented by 256, + * so we don't touch the lowest byte and instead treat it as + * an increment of one starting with the next byte. + */ + for(size_t i = 0; i != 256; ++i) + { + for(size_t j = 1; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) + break; + } + + permutation->encrypt_n(&counter[0], &buffer[0], 256); + + position = 0; + } + +} +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* +* OFB Constructor +*/ +OFB::OFB(BlockCipher* ciph) : permutation(ciph) + { + position = 0; + buffer.resize(permutation->block_size()); + } + +/* +* OFB Destructor +*/ +OFB::~OFB() + { + delete permutation; + } + +/* +* Zeroize +*/ +void OFB::clear() + { + permutation->clear(); + zeroise(buffer); + position = 0; + } + +/* +* Set the key +*/ +void OFB::key_schedule(const byte key[], size_t key_len) + { + permutation->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(0, 0); + } + +/* +* Return the name of this type +*/ +std::string OFB::name() const + { + return ("OFB(" + permutation->name() + ")"); + } + +/* +* CTR-BE Encryption/Decryption +*/ +void OFB::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + permutation->encrypt(buffer); + position = 0; + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Set CTR-BE IV +*/ +void OFB::set_iv(const byte iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + zeroise(buffer); + buffer.copy(0, iv, iv_len); + + permutation->encrypt(buffer); + position = 0; + } + +} +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \ + do { \ + x2 ^= rotate_left(x1 + x4, 7); \ + x3 ^= rotate_left(x2 + x1, 9); \ + x4 ^= rotate_left(x3 + x2, 13); \ + x1 ^= rotate_left(x4 + x3, 18); \ + } while(0) + +/* +* Generate HSalsa20 cipher stream (for XSalsa20 IV setup) +*/ +void hsalsa20(u32bit output[8], const u32bit input[16]) + { + u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + output[0] = x00; + output[1] = x05; + output[2] = x10; + output[3] = x15; + output[4] = x06; + output[5] = x07; + output[6] = x08; + output[7] = x09; + } + +/* +* Generate Salsa20 cipher stream +*/ +void salsa20(byte output[64], const u32bit input[16]) + { + u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + store_le(x00 + input[ 0], output + 4 * 0); + store_le(x01 + input[ 1], output + 4 * 1); + store_le(x02 + input[ 2], output + 4 * 2); + store_le(x03 + input[ 3], output + 4 * 3); + store_le(x04 + input[ 4], output + 4 * 4); + store_le(x05 + input[ 5], output + 4 * 5); + store_le(x06 + input[ 6], output + 4 * 6); + store_le(x07 + input[ 7], output + 4 * 7); + store_le(x08 + input[ 8], output + 4 * 8); + store_le(x09 + input[ 9], output + 4 * 9); + store_le(x10 + input[10], output + 4 * 10); + store_le(x11 + input[11], output + 4 * 11); + store_le(x12 + input[12], output + 4 * 12); + store_le(x13 + input[13], output + 4 * 13); + store_le(x14 + input[14], output + 4 * 14); + store_le(x15 + input[15], output + 4 * 15); + } + +} + +/* +* Combine cipher stream with message +*/ +void Salsa20::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + salsa20(&buffer[0], &state[0]); + + ++state[8]; + if(!state[8]) // if overflow in state[8] + ++state[9]; // carry to state[9] + + position = 0; + } + + xor_buf(out, in, &buffer[position], length); + + position += length; + } + +/* +* Salsa20 Key Schedule +*/ +void Salsa20::key_schedule(const byte key[], size_t length) + { + static const u32bit TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const u32bit SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + clear(); + + if(length == 16) + { + state[0] = TAU[0]; + state[1] = load_le(key, 0); + state[2] = load_le(key, 1); + state[3] = load_le(key, 2); + state[4] = load_le(key, 3); + state[5] = TAU[1]; + state[10] = TAU[2]; + state[11] = load_le(key, 0); + state[12] = load_le(key, 1); + state[13] = load_le(key, 2); + state[14] = load_le(key, 3); + state[15] = TAU[3]; + } + else if(length == 32) + { + state[0] = SIGMA[0]; + state[1] = load_le(key, 0); + state[2] = load_le(key, 1); + state[3] = load_le(key, 2); + state[4] = load_le(key, 3); + state[5] = SIGMA[1]; + state[10] = SIGMA[2]; + state[11] = load_le(key, 4); + state[12] = load_le(key, 5); + state[13] = load_le(key, 6); + state[14] = load_le(key, 7); + state[15] = SIGMA[3]; + } + + const byte ZERO[8] = { 0 }; + set_iv(ZERO, sizeof(ZERO)); + } + +/* +* Return the name of this type +*/ +void Salsa20::set_iv(const byte iv[], size_t length) + { + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + if(length == 8) + { + // Salsa20 + state[6] = load_le(iv, 0); + state[7] = load_le(iv, 1); + } + else + { + // XSalsa20 + state[6] = load_le(iv, 0); + state[7] = load_le(iv, 1); + state[8] = load_le(iv, 2); + state[9] = load_le(iv, 3); + + SecureVector hsalsa(8); + hsalsa20(&hsalsa[0], &state[0]); + + state[ 1] = hsalsa[0]; + state[ 2] = hsalsa[1]; + state[ 3] = hsalsa[2]; + state[ 4] = hsalsa[3]; + state[ 6] = load_le(iv, 4); + state[ 7] = load_le(iv, 5); + state[11] = hsalsa[4]; + state[12] = hsalsa[5]; + state[13] = hsalsa[6]; + state[14] = hsalsa[7]; + } + + state[8] = 0; + state[9] = 0; + + salsa20(&buffer[0], &state[0]); + ++state[8]; + if(!state[8]) // if overflow in state[8] + ++state[9]; // carry to state[9] + + position = 0; + } + +/* +* Return the name of this type +*/ +std::string Salsa20::name() const + { + return "Salsa20"; + } + +/* +* Clear memory of sensitive data +*/ +void Salsa20::clear() + { + zeroise(state); + zeroise(buffer); + position = 0; + } + +} +/* +* Stream Cipher +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +void StreamCipher::set_iv(const byte[], size_t iv_len) + { + if(iv_len) + throw Invalid_Argument("The stream cipher " + name() + + " does not support resyncronization"); + } + +bool StreamCipher::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0); + } + +} +/* +* Tables for Turing +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +const byte Turing::SBOX[256] = { + 0x61, 0x51, 0xEB, 0x19, 0xB9, 0x5D, 0x60, 0x38, 0x7C, 0xB2, 0x06, 0x12, + 0xC4, 0x5B, 0x16, 0x3B, 0x2B, 0x18, 0x83, 0xB0, 0x7F, 0x75, 0xFA, 0xA0, + 0xE9, 0xDD, 0x6D, 0x7A, 0x6B, 0x68, 0x2D, 0x49, 0xB5, 0x1C, 0x90, 0xF7, + 0xED, 0x9F, 0xE8, 0xCE, 0xAE, 0x77, 0xC2, 0x13, 0xFD, 0xCD, 0x3E, 0xCF, + 0x37, 0x6A, 0xD4, 0xDB, 0x8E, 0x65, 0x1F, 0x1A, 0x87, 0xCB, 0x40, 0x15, + 0x88, 0x0D, 0x35, 0xB3, 0x11, 0x0F, 0xD0, 0x30, 0x48, 0xF9, 0xA8, 0xAC, + 0x85, 0x27, 0x0E, 0x8A, 0xE0, 0x50, 0x64, 0xA7, 0xCC, 0xE4, 0xF1, 0x98, + 0xFF, 0xA1, 0x04, 0xDA, 0xD5, 0xBC, 0x1B, 0xBB, 0xD1, 0xFE, 0x31, 0xCA, + 0xBA, 0xD9, 0x2E, 0xF3, 0x1D, 0x47, 0x4A, 0x3D, 0x71, 0x4C, 0xAB, 0x7D, + 0x8D, 0xC7, 0x59, 0xB8, 0xC1, 0x96, 0x1E, 0xFC, 0x44, 0xC8, 0x7B, 0xDC, + 0x5C, 0x78, 0x2A, 0x9D, 0xA5, 0xF0, 0x73, 0x22, 0x89, 0x05, 0xF4, 0x07, + 0x21, 0x52, 0xA6, 0x28, 0x9A, 0x92, 0x69, 0x8F, 0xC5, 0xC3, 0xF5, 0xE1, + 0xDE, 0xEC, 0x09, 0xF2, 0xD3, 0xAF, 0x34, 0x23, 0xAA, 0xDF, 0x7E, 0x82, + 0x29, 0xC0, 0x24, 0x14, 0x03, 0x32, 0x4E, 0x39, 0x6F, 0xC6, 0xB1, 0x9B, + 0xEA, 0x72, 0x79, 0x41, 0xD8, 0x26, 0x6C, 0x5E, 0x2C, 0xB4, 0xA2, 0x53, + 0x57, 0xE2, 0x9C, 0x86, 0x54, 0x95, 0xB6, 0x80, 0x8C, 0x36, 0x67, 0xBD, + 0x08, 0x93, 0x2F, 0x99, 0x5A, 0xF8, 0x3A, 0xD7, 0x56, 0x84, 0xD2, 0x01, + 0xF6, 0x66, 0x4D, 0x55, 0x8B, 0x0C, 0x0B, 0x46, 0xB7, 0x3C, 0x45, 0x91, + 0xA4, 0xE3, 0x70, 0xD6, 0xFB, 0xE6, 0x10, 0xA9, 0xC9, 0x00, 0x9E, 0xE7, + 0x4F, 0x76, 0x25, 0x3F, 0x5F, 0xA3, 0x33, 0x20, 0x02, 0xEF, 0x62, 0x74, + 0xEE, 0x17, 0x81, 0x42, 0x58, 0x0A, 0x4B, 0x63, 0xE5, 0xBE, 0x6E, 0xAD, + 0xBF, 0x43, 0x94, 0x97 }; + +const u32bit Turing::Q_BOX[256] = { + 0x1FAA1887, 0x4E5E435C, 0x9165C042, 0x250E6EF4, 0x5957EE20, 0xD484FED3, + 0xA666C502, 0x7E54E8AE, 0xD12EE9D9, 0xFC1F38D4, 0x49829B5D, 0x1B5CDF3C, + 0x74864249, 0xDA2E3963, 0x28F4429F, 0xC8432C35, 0x4AF40325, 0x9FC0DD70, + 0xD8973DED, 0x1A02DC5E, 0xCD175B42, 0xF10012BF, 0x6694D78C, 0xACAAB26B, + 0x4EC11B9A, 0x3F168146, 0xC0EA8EC5, 0xB38AC28F, 0x1FED5C0F, 0xAAB4101C, + 0xEA2DB082, 0x470929E1, 0xE71843DE, 0x508299FC, 0xE72FBC4B, 0x2E3915DD, + 0x9FA803FA, 0x9546B2DE, 0x3C233342, 0x0FCEE7C3, 0x24D607EF, 0x8F97EBAB, + 0xF37F859B, 0xCD1F2E2F, 0xC25B71DA, 0x75E2269A, 0x1E39C3D1, 0xEDA56B36, + 0xF8C9DEF2, 0x46C9FC5F, 0x1827B3A3, 0x70A56DDF, 0x0D25B510, 0x000F85A7, + 0xB2E82E71, 0x68CB8816, 0x8F951E2A, 0x72F5F6AF, 0xE4CBC2B3, 0xD34FF55D, + 0x2E6B6214, 0x220B83E3, 0xD39EA6F5, 0x6FE041AF, 0x6B2F1F17, 0xAD3B99EE, + 0x16A65EC0, 0x757016C6, 0xBA7709A4, 0xB0326E01, 0xF4B280D9, 0x4BFB1418, + 0xD6AFF227, 0xFD548203, 0xF56B9D96, 0x6717A8C0, 0x00D5BF6E, 0x10EE7888, + 0xEDFCFE64, 0x1BA193CD, 0x4B0D0184, 0x89AE4930, 0x1C014F36, 0x82A87088, + 0x5EAD6C2A, 0xEF22C678, 0x31204DE7, 0xC9C2E759, 0xD200248E, 0x303B446B, + 0xB00D9FC2, 0x9914A895, 0x906CC3A1, 0x54FEF170, 0x34C19155, 0xE27B8A66, + 0x131B5E69, 0xC3A8623E, 0x27BDFA35, 0x97F068CC, 0xCA3A6ACD, 0x4B55E936, + 0x86602DB9, 0x51DF13C1, 0x390BB16D, 0x5A80B83C, 0x22B23763, 0x39D8A911, + 0x2CB6BC13, 0xBF5579D7, 0x6C5C2FA8, 0xA8F4196E, 0xBCDB5476, 0x6864A866, + 0x416E16AD, 0x897FC515, 0x956FEB3C, 0xF6C8A306, 0x216799D9, 0x171A9133, + 0x6C2466DD, 0x75EB5DCD, 0xDF118F50, 0xE4AFB226, 0x26B9CEF3, 0xADB36189, + 0x8A7A19B1, 0xE2C73084, 0xF77DED5C, 0x8B8BC58F, 0x06DDE421, 0xB41E47FB, + 0xB1CC715E, 0x68C0FF99, 0x5D122F0F, 0xA4D25184, 0x097A5E6C, 0x0CBF18BC, + 0xC2D7C6E0, 0x8BB7E420, 0xA11F523F, 0x35D9B8A2, 0x03DA1A6B, 0x06888C02, + 0x7DD1E354, 0x6BBA7D79, 0x32CC7753, 0xE52D9655, 0xA9829DA1, 0x301590A7, + 0x9BC1C149, 0x13537F1C, 0xD3779B69, 0x2D71F2B7, 0x183C58FA, 0xACDC4418, + 0x8D8C8C76, 0x2620D9F0, 0x71A80D4D, 0x7A74C473, 0x449410E9, 0xA20E4211, + 0xF9C8082B, 0x0A6B334A, 0xB5F68ED2, 0x8243CC1B, 0x453C0FF3, 0x9BE564A0, + 0x4FF55A4F, 0x8740F8E7, 0xCCA7F15F, 0xE300FE21, 0x786D37D6, 0xDFD506F1, + 0x8EE00973, 0x17BBDE36, 0x7A670FA8, 0x5C31AB9E, 0xD4DAB618, 0xCC1F52F5, + 0xE358EB4F, 0x19B9E343, 0x3A8D77DD, 0xCDB93DA6, 0x140FD52D, 0x395412F8, + 0x2BA63360, 0x37E53AD0, 0x80700F1C, 0x7624ED0B, 0x703DC1EC, 0xB7366795, + 0xD6549D15, 0x66CE46D7, 0xD17ABE76, 0xA448E0A0, 0x28F07C02, 0xC31249B7, + 0x6E9ED6BA, 0xEAA47F78, 0xBBCFFFBD, 0xC507CA84, 0xE965F4DA, 0x8E9F35DA, + 0x6AD2AA44, 0x577452AC, 0xB5D674A7, 0x5461A46A, 0x6763152A, 0x9C12B7AA, + 0x12615927, 0x7B4FB118, 0xC351758D, 0x7E81687B, 0x5F52F0B3, 0x2D4254ED, + 0xD4C77271, 0x0431ACAB, 0xBEF94AEC, 0xFEE994CD, 0x9C4D9E81, 0xED623730, + 0xCF8A21E8, 0x51917F0B, 0xA7A9B5D6, 0xB297ADF8, 0xEED30431, 0x68CAC921, + 0xF1B35D46, 0x7A430A36, 0x51194022, 0x9ABCA65E, 0x85EC70BA, 0x39AEA8CC, + 0x737BAE8B, 0x582924D5, 0x03098A5A, 0x92396B81, 0x18DE2522, 0x745C1CB8, + 0xA1B8FE1D, 0x5DB3C697, 0x29164F83, 0x97C16376, 0x8419224C, 0x21203B35, + 0x833AC0FE, 0xD966A19A, 0xAAF0B24F, 0x40FDA998, 0xE7D52D71, 0x390896A8, + 0xCEE6053F, 0xD0B0D300, 0xFF99CBCC, 0x065E3D40 }; + +} +/* +* Turing +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +namespace { + +/* +* Perform an N-way PHT +*/ +inline void PHT(MemoryRegion& B) + { + u32bit sum = 0; + for(size_t i = 0; i < B.size() - 1; ++i) + sum += B[i]; + + B[B.size()-1] += sum; + + sum = B[B.size()-1]; + for(size_t i = 0; i < B.size() - 1; ++i) + B[i] += sum; + } + +} + +/* +* Combine cipher stream with message +*/ +void Turing::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + generate(); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Generate cipher stream +*/ +void Turing::generate() + { + // Table for Turing's polynomial multiplication + static const u32bit MULT_TAB[256] = { + 0x00000000, 0xD02B4367, 0xED5686CE, 0x3D7DC5A9, 0x97AC41D1, 0x478702B6, + 0x7AFAC71F, 0xAAD18478, 0x631582EF, 0xB33EC188, 0x8E430421, 0x5E684746, + 0xF4B9C33E, 0x24928059, 0x19EF45F0, 0xC9C40697, 0xC62A4993, 0x16010AF4, + 0x2B7CCF5D, 0xFB578C3A, 0x51860842, 0x81AD4B25, 0xBCD08E8C, 0x6CFBCDEB, + 0xA53FCB7C, 0x7514881B, 0x48694DB2, 0x98420ED5, 0x32938AAD, 0xE2B8C9CA, + 0xDFC50C63, 0x0FEE4F04, 0xC154926B, 0x117FD10C, 0x2C0214A5, 0xFC2957C2, + 0x56F8D3BA, 0x86D390DD, 0xBBAE5574, 0x6B851613, 0xA2411084, 0x726A53E3, + 0x4F17964A, 0x9F3CD52D, 0x35ED5155, 0xE5C61232, 0xD8BBD79B, 0x089094FC, + 0x077EDBF8, 0xD755989F, 0xEA285D36, 0x3A031E51, 0x90D29A29, 0x40F9D94E, + 0x7D841CE7, 0xADAF5F80, 0x646B5917, 0xB4401A70, 0x893DDFD9, 0x59169CBE, + 0xF3C718C6, 0x23EC5BA1, 0x1E919E08, 0xCEBADD6F, 0xCFA869D6, 0x1F832AB1, + 0x22FEEF18, 0xF2D5AC7F, 0x58042807, 0x882F6B60, 0xB552AEC9, 0x6579EDAE, + 0xACBDEB39, 0x7C96A85E, 0x41EB6DF7, 0x91C02E90, 0x3B11AAE8, 0xEB3AE98F, + 0xD6472C26, 0x066C6F41, 0x09822045, 0xD9A96322, 0xE4D4A68B, 0x34FFE5EC, + 0x9E2E6194, 0x4E0522F3, 0x7378E75A, 0xA353A43D, 0x6A97A2AA, 0xBABCE1CD, + 0x87C12464, 0x57EA6703, 0xFD3BE37B, 0x2D10A01C, 0x106D65B5, 0xC04626D2, + 0x0EFCFBBD, 0xDED7B8DA, 0xE3AA7D73, 0x33813E14, 0x9950BA6C, 0x497BF90B, + 0x74063CA2, 0xA42D7FC5, 0x6DE97952, 0xBDC23A35, 0x80BFFF9C, 0x5094BCFB, + 0xFA453883, 0x2A6E7BE4, 0x1713BE4D, 0xC738FD2A, 0xC8D6B22E, 0x18FDF149, + 0x258034E0, 0xF5AB7787, 0x5F7AF3FF, 0x8F51B098, 0xB22C7531, 0x62073656, + 0xABC330C1, 0x7BE873A6, 0x4695B60F, 0x96BEF568, 0x3C6F7110, 0xEC443277, + 0xD139F7DE, 0x0112B4B9, 0xD31DD2E1, 0x03369186, 0x3E4B542F, 0xEE601748, + 0x44B19330, 0x949AD057, 0xA9E715FE, 0x79CC5699, 0xB008500E, 0x60231369, + 0x5D5ED6C0, 0x8D7595A7, 0x27A411DF, 0xF78F52B8, 0xCAF29711, 0x1AD9D476, + 0x15379B72, 0xC51CD815, 0xF8611DBC, 0x284A5EDB, 0x829BDAA3, 0x52B099C4, + 0x6FCD5C6D, 0xBFE61F0A, 0x7622199D, 0xA6095AFA, 0x9B749F53, 0x4B5FDC34, + 0xE18E584C, 0x31A51B2B, 0x0CD8DE82, 0xDCF39DE5, 0x1249408A, 0xC26203ED, + 0xFF1FC644, 0x2F348523, 0x85E5015B, 0x55CE423C, 0x68B38795, 0xB898C4F2, + 0x715CC265, 0xA1778102, 0x9C0A44AB, 0x4C2107CC, 0xE6F083B4, 0x36DBC0D3, + 0x0BA6057A, 0xDB8D461D, 0xD4630919, 0x04484A7E, 0x39358FD7, 0xE91ECCB0, + 0x43CF48C8, 0x93E40BAF, 0xAE99CE06, 0x7EB28D61, 0xB7768BF6, 0x675DC891, + 0x5A200D38, 0x8A0B4E5F, 0x20DACA27, 0xF0F18940, 0xCD8C4CE9, 0x1DA70F8E, + 0x1CB5BB37, 0xCC9EF850, 0xF1E33DF9, 0x21C87E9E, 0x8B19FAE6, 0x5B32B981, + 0x664F7C28, 0xB6643F4F, 0x7FA039D8, 0xAF8B7ABF, 0x92F6BF16, 0x42DDFC71, + 0xE80C7809, 0x38273B6E, 0x055AFEC7, 0xD571BDA0, 0xDA9FF2A4, 0x0AB4B1C3, + 0x37C9746A, 0xE7E2370D, 0x4D33B375, 0x9D18F012, 0xA06535BB, 0x704E76DC, + 0xB98A704B, 0x69A1332C, 0x54DCF685, 0x84F7B5E2, 0x2E26319A, 0xFE0D72FD, + 0xC370B754, 0x135BF433, 0xDDE1295C, 0x0DCA6A3B, 0x30B7AF92, 0xE09CECF5, + 0x4A4D688D, 0x9A662BEA, 0xA71BEE43, 0x7730AD24, 0xBEF4ABB3, 0x6EDFE8D4, + 0x53A22D7D, 0x83896E1A, 0x2958EA62, 0xF973A905, 0xC40E6CAC, 0x14252FCB, + 0x1BCB60CF, 0xCBE023A8, 0xF69DE601, 0x26B6A566, 0x8C67211E, 0x5C4C6279, + 0x6131A7D0, 0xB11AE4B7, 0x78DEE220, 0xA8F5A147, 0x958864EE, 0x45A32789, + 0xEF72A3F1, 0x3F59E096, 0x0224253F, 0xD20F6658 }; + + /* + I tried an implementation without precomputed LFSR offsets, since + I thought that might allow (especially on x86-64) the use of leal to + compute all the offsets.. However on my Core2 with GCC 4.3 it + turned out significantly slower (238 Mib/s, versus 300 Mib/s + with precomputed offsets) + + I also tried using byte vs u32bit for the offset variable (since + x86 memory addressing modes can be odd), but it made things even + slower (186 Mib/s) + */ + static const byte OFFSETS[221] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 14, 15, 16, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 2, 3, 4, + 10, 11, 12, 13, 14, 15, 16, 0, 1, 5, 7, 8, 9, + 15, 16, 0, 1, 2, 3, 4, 5, 6, 10, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 0, 1, 2, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 3, 5, 6, 7, + 13, 14, 15, 16, 0, 1, 2, 3, 4, 8, 10, 11, 12, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 15, 16, 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 3, 4, 5, + 11, 12, 13, 14, 15, 16, 0, 1, 2, 6, 8, 9, 10, + 16, 0, 1, 2, 3, 4, 5, 6, 7, 11, 13, 14, 15, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 1, 2, 3, + 9, 10, 11, 12, 13, 14, 15, 16, 0, 4, 6, 7, 8, + 14, 15, 16, 0, 1, 2, 3, 4, 5, 9, 11, 12, 13, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 16, 0, 1, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 2, 4, 5, 6, + 12, 13, 14, 15, 16, 0, 1, 2, 3, 7, 9, 10, 11 }; + + for(size_t i = 0; i != 17; ++i) + { + const byte* R_off = OFFSETS + 13*i; + + u32bit R0 = R[R_off[0]]; + u32bit R1 = R[R_off[1]]; + u32bit R2 = R[R_off[2]]; + u32bit R3 = R[R_off[3]]; + u32bit R4 = R[R_off[4]]; + + const u32bit R5 = R[R_off[5]]; + const u32bit R6 = R[R_off[6]]; + const u32bit R7 = R[R_off[7]]; + const u32bit R8 = R[R_off[8]]; + const u32bit R9 = R[R_off[9]]; + const u32bit R10 = R[R_off[10]]; + const u32bit R11 = R[R_off[11]]; + const u32bit R12 = R[R_off[12]]; + + R[R_off[0]] = R0 = ((R0 << 8) ^ MULT_TAB[(R0 >> 24) & 0xFF]) ^ R11 ^ R4; + + u32bit A = R0; + u32bit B = R10; + u32bit C = R7; + u32bit D = R2; + u32bit E = R1; + + E += A + B + C + D; + + A += E; + B += E; + C += E; + D += E; + + A = S0[get_byte(0, A)] ^ S1[get_byte(1, A)] ^ + S2[get_byte(2, A)] ^ S3[get_byte(3, A)]; + B = S0[get_byte(1, B)] ^ S1[get_byte(2, B)] ^ + S2[get_byte(3, B)] ^ S3[get_byte(0, B)]; + C = S0[get_byte(2, C)] ^ S1[get_byte(3, C)] ^ + S2[get_byte(0, C)] ^ S3[get_byte(1, C)]; + D = S0[get_byte(3, D)] ^ S1[get_byte(0, D)] ^ + S2[get_byte(1, D)] ^ S3[get_byte(2, D)]; + E = S0[get_byte(0, E)] ^ S1[get_byte(1, E)] ^ + S2[get_byte(2, E)] ^ S3[get_byte(3, E)]; + + E += A + B + C + D; + + A += E; + B += E; + C += E; + D += E; + + R[R_off[1]] = R1 = ((R1 << 8) ^ MULT_TAB[(R1 >> 24) & 0xFF]) ^ R12 ^ R5; + R[R_off[2]] = R2 = ((R2 << 8) ^ MULT_TAB[(R2 >> 24) & 0xFF]) ^ R0 ^ R6; + R[R_off[3]] = ((R3 << 8) ^ MULT_TAB[(R3 >> 24) & 0xFF]) ^ R1 ^ R7; + + E += R4; + + R[R_off[4]] = ((R4 << 8) ^ MULT_TAB[(R4 >> 24) & 0xFF]) ^ R2 ^ R8; + + A += R1; + B += R12; + C += R9; + D += R5; + + store_be(A, &buffer[20*i + 0]); + store_be(B, &buffer[20*i + 4]); + store_be(C, &buffer[20*i + 8]); + store_be(D, &buffer[20*i + 12]); + store_be(E, &buffer[20*i + 16]); + } + + position = 0; + } + +/* +* Turing's byte mixing step +*/ +u32bit Turing::fixedS(u32bit W) + { + byte B = SBOX[get_byte(0, W)]; + W ^= Q_BOX[B]; + W &= 0x00FFFFFF; + W |= B << 24; + + B = SBOX[get_byte(1, W)]; + W ^= rotate_left(Q_BOX[B], 8); + W &= 0xFF00FFFF; + W |= B << 16; + + B = SBOX[get_byte(2, W)]; + W ^= rotate_left(Q_BOX[B], 16); + W &= 0xFFFF00FF; + W |= B << 8; + + B = SBOX[get_byte(3, W)]; + W ^= rotate_left(Q_BOX[B], 24); + W &= 0xFFFFFF00; + W |= B; + + return W; + } + +/* +* Turing Key Schedule +*/ +void Turing::key_schedule(const byte key[], size_t length) + { + K.resize(length / 4); + for(size_t i = 0; i != length; ++i) + K[i/4] = (K[i/4] << 8) + key[i]; + + for(size_t i = 0; i != K.size(); ++i) + K[i] = fixedS(K[i]); + + PHT(K); + + for(u32bit i = 0; i != 256; ++i) + { + u32bit W0 = 0, C0 = i; + u32bit W1 = 0, C1 = i; + u32bit W2 = 0, C2 = i; + u32bit W3 = 0, C3 = i; + + for(size_t j = 0; j < K.size(); ++j) + { + C0 = SBOX[get_byte(0, K[j]) ^ C0]; + C1 = SBOX[get_byte(1, K[j]) ^ C1]; + C2 = SBOX[get_byte(2, K[j]) ^ C2]; + C3 = SBOX[get_byte(3, K[j]) ^ C3]; + + W0 ^= rotate_left(Q_BOX[C0], j); + W1 ^= rotate_left(Q_BOX[C1], j + 8); + W2 ^= rotate_left(Q_BOX[C2], j + 16); + W3 ^= rotate_left(Q_BOX[C3], j + 24); + } + + S0[i] = (W0 & 0x00FFFFFF) | (C0 << 24); + S1[i] = (W1 & 0xFF00FFFF) | (C1 << 16); + S2[i] = (W2 & 0xFFFF00FF) | (C2 << 8); + S3[i] = (W3 & 0xFFFFFF00) | C3; + } + + set_iv(0, 0); + } + +/* +* Resynchronization +*/ +void Turing::set_iv(const byte iv[], size_t length) + { + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + SecureVector IV(length / 4); + for(size_t i = 0; i != length; ++i) + IV[i/4] = (IV[i/4] << 8) + iv[i]; + + for(size_t i = 0; i != IV.size(); ++i) + R[i] = IV[i] = fixedS(IV[i]); + + for(size_t i = 0; i != K.size(); ++i) + R[i+IV.size()] = K[i]; + + R[K.size() + IV.size()] = (0x010203 << 8) | (K.size() << 4) | IV.size(); + + for(size_t i = K.size() + IV.size() + 1; i != 17; ++i) + { + const u32bit W = R[i-K.size()-IV.size()-1] + R[i-1]; + R[i] = S0[get_byte(0, W)] ^ S1[get_byte(1, W)] ^ + S2[get_byte(2, W)] ^ S3[get_byte(3, W)]; + } + + PHT(R); + + generate(); + } + +/* +* Clear memory of sensitive data +*/ +void Turing::clear() + { + zeroise(S0); + zeroise(S1); + zeroise(S2); + zeroise(S3); + + zeroise(buffer); + position = 0; + } + +} +/* +* WiderWake +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Combine cipher stream with message +*/ +void WiderWake_41_BE::cipher(const byte in[], byte out[], size_t length) + { + while(length >= buffer.size() - position) + { + xor_buf(out, in, &buffer[position], buffer.size() - position); + length -= (buffer.size() - position); + in += (buffer.size() - position); + out += (buffer.size() - position); + generate(buffer.size()); + } + xor_buf(out, in, &buffer[position], length); + position += length; + } + +/* +* Generate cipher stream +*/ +void WiderWake_41_BE::generate(size_t length) + { + u32bit R0 = state[0], R1 = state[1], + R2 = state[2], R3 = state[3], + R4 = state[4]; + + for(size_t i = 0; i != length; i += 8) + { + u32bit R0a; + + store_be(R3, &buffer[i]); + + R0a = R4 + R3; R3 += R2; R2 += R1; R1 += R0; + R0a = (R0a >> 8) ^ T[(R0a & 0xFF)]; + R1 = (R1 >> 8) ^ T[(R1 & 0xFF)]; + R2 = (R2 >> 8) ^ T[(R2 & 0xFF)]; + R3 = (R3 >> 8) ^ T[(R3 & 0xFF)]; + R4 = R0; R0 = R0a; + + store_be(R3, &buffer[i + 4]); + + R0a = R4 + R3; R3 += R2; R2 += R1; R1 += R0; + R0a = (R0a >> 8) ^ T[(R0a & 0xFF)]; + R1 = (R1 >> 8) ^ T[(R1 & 0xFF)]; + R2 = (R2 >> 8) ^ T[(R2 & 0xFF)]; + R3 = (R3 >> 8) ^ T[(R3 & 0xFF)]; + R4 = R0; R0 = R0a; + } + + state[0] = R0; + state[1] = R1; + state[2] = R2; + state[3] = R3; + state[4] = R4; + + position = 0; + } + +/* +* WiderWake Key Schedule +*/ +void WiderWake_41_BE::key_schedule(const byte key[], size_t) + { + for(size_t i = 0; i != 4; ++i) + t_key[i] = load_be(key, i); + + static const u32bit MAGIC[8] = { + 0x726A8F3B, 0xE69A3B5C, 0xD3C71FE5, 0xAB3C73D2, + 0x4D3A8EB3, 0x0396D6E8, 0x3D4C2F7A, 0x9EE27CF3 }; + + for(size_t i = 0; i != 4; ++i) + T[i] = t_key[i]; + + for(size_t i = 4; i != 256; ++i) + { + u32bit X = T[i-1] + T[i-4]; + T[i] = (X >> 3) ^ MAGIC[X % 8]; + } + + for(size_t i = 0; i != 23; ++i) + T[i] += T[i+89]; + + u32bit X = T[33]; + u32bit Z = (T[59] | 0x01000001) & 0xFF7FFFFF; + for(size_t i = 0; i != 256; ++i) + { + X = (X & 0xFF7FFFFF) + Z; + T[i] = (T[i] & 0x00FFFFFF) ^ X; + } + + X = (T[X & 0xFF] ^ X) & 0xFF; + Z = T[0]; + T[0] = T[X]; + for(size_t i = 1; i != 256; ++i) + { + T[X] = T[i]; + X = (T[i ^ X] ^ X) & 0xFF; + T[i] = T[X]; + } + T[X] = Z; + + position = 0; + + const byte ZEROS[8] = { 0 }; + set_iv(ZEROS, sizeof(ZEROS)); + } + +/* +* Resynchronization +*/ +void WiderWake_41_BE::set_iv(const byte iv[], size_t length) + { + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + for(size_t i = 0; i != 4; ++i) + state[i] = t_key[i]; + + state[4] = load_be(iv, 0); + state[0] ^= state[4]; + state[2] ^= load_be(iv, 1); + + generate(8*4); + generate(buffer.size()); + } + +/* +* Clear memory of sensitive data +*/ +void WiderWake_41_BE::clear() + { + position = 0; + zeroise(t_key); + zeroise(state); + zeroise(T); + zeroise(buffer); + } + +} +/* +* Runtime assertion checking +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +void assertion_failure(const char* expr_str, + const char* msg, + const char* func, + const char* file, + int line) + { + std::ostringstream format; + + format << "Assertion " << expr_str << " failed "; + + if(msg) + format << "(" << msg << ") "; + + if(func) + format << "in " << func << " "; + + format << "@" << file << ":" << line; + + throw Internal_Error(format.str()); + } + +} +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +namespace Charset { + +namespace { + +/* +* Convert from UCS-2 to ISO 8859-1 +*/ +std::string ucs2_to_latin1(const std::string& ucs2) + { + if(ucs2.size() % 2 == 1) + throw Decoding_Error("UCS-2 string has an odd number of bytes"); + + std::string latin1; + + for(size_t i = 0; i != ucs2.size(); i += 2) + { + const byte c1 = ucs2[i]; + const byte c2 = ucs2[i+1]; + + if(c1 != 0) + throw Decoding_Error("UCS-2 has non-Latin1 characters"); + + latin1 += static_cast(c2); + } + + return latin1; + } + +/* +* Convert from UTF-8 to ISO 8859-1 +*/ +std::string utf8_to_latin1(const std::string& utf8) + { + std::string iso8859; + + size_t position = 0; + while(position != utf8.size()) + { + const byte c1 = static_cast(utf8[position++]); + + if(c1 <= 0x7F) + iso8859 += static_cast(c1); + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const byte c2 = static_cast(utf8[position++]); + const byte iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); + + if(iso_char <= 0x7F) + throw Decoding_Error("UTF-8: sequence longer than needed"); + + iso8859 += static_cast(iso_char); + } + else + throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); + } + + return iso8859; + } + +/* +* Convert from ISO 8859-1 to UTF-8 +*/ +std::string latin1_to_utf8(const std::string& iso8859) + { + std::string utf8; + for(size_t i = 0; i != iso8859.size(); ++i) + { + const byte c = static_cast(iso8859[i]); + + if(c <= 0x7F) + utf8 += static_cast(c); + else + { + utf8 += static_cast((0xC0 | (c >> 6))); + utf8 += static_cast((0x80 | (c & 0x3F))); + } + } + return utf8; + } + +} + +/* +* Perform character set transcoding +*/ +std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + if(to == LOCAL_CHARSET) + to = LATIN1_CHARSET; + if(from == LOCAL_CHARSET) + from = LATIN1_CHARSET; + + if(to == from) + return str; + + if(from == LATIN1_CHARSET && to == UTF8_CHARSET) + return latin1_to_utf8(str); + if(from == UTF8_CHARSET && to == LATIN1_CHARSET) + return utf8_to_latin1(str); + if(from == UCS2_CHARSET && to == LATIN1_CHARSET) + return ucs2_to_latin1(str); + + throw Invalid_Argument("Unknown transcoding operation from " + + to_string(from) + " to " + to_string(to)); + } + +/* +* Check if a character represents a digit +*/ +bool is_digit(char c) + { + if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9') + return true; + return false; + } + +/* +* Check if a character represents whitespace +*/ +bool is_space(char c) + { + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; + } + +/* +* Convert a character to a digit +*/ +byte char2digit(char c) + { + switch(c) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); + } + +/* +* Convert a digit to a character +*/ +char digit2char(byte b) + { + switch(b) + { + case 0: return '0'; + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + case 8: return '8'; + case 9: return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/* +* Case-insensitive character comparison +*/ +bool caseless_cmp(char a, char b) + { + return (std::tolower(static_cast(a)) == + std::tolower(static_cast(b))); + } + +} + +} +/* +* Runtime CPU detection +* (C) 2009-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_DARWIN) + #include +#endif + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include + #include + #include +#endif + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + + #include + #define CALL_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + + #include + #define CALL_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) && (BOTAN_GCC_VERSION >= 430) + + // Only available starting in GCC 4.3 + #include + +namespace { + + /* + * Prevent inlining to work around GCC bug 44174 + */ + void __attribute__((__noinline__)) call_gcc_cpuid(Botan::u32bit type, + Botan::u32bit out[4]) + { + __get_cpuid(type, out, out+1, out+2, out+3); + } + + #define CALL_CPUID call_gcc_cpuid + +} + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && \ + (defined(BOTAN_BUILD_COMPILER_IS_CLANG) || defined(BOTAN_BUILD_COMPILER_IS_GCC)) + + /* + * We can't safely use this on x86-32 as some 32-bit ABIs use ebx as + * a PIC register, and in theory there are some x86-32s still out + * there that don't support cpuid at all; it requires strange + * contortions to detect them. + */ + + #define CALL_CPUID(type, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type)) + +#else + #warning "No method of calling CPUID for this compiler" +#endif + +#endif + +#ifndef CALL_CPUID + // In all other cases, just zeroize the supposed cpuid output + #define CALL_CPUID(type, out) \ + do { out[0] = out[1] = out[2] = out[3] = 0; } while(0); +#endif + +namespace Botan { + +u64bit CPUID::x86_processor_flags = 0; +size_t CPUID::cache_line = 32; +bool CPUID::altivec_capable = false; + +namespace { + +u32bit get_x86_cache_line_size() + { + const u32bit INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; + const u32bit AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; + + u32bit cpuid[4] = { 0 }; + CALL_CPUID(0, cpuid); + + if(same_mem(cpuid + 1, INTEL_CPUID, 3)) + { + CALL_CPUID(1, cpuid); + return 8 * get_byte(2, cpuid[1]); + } + else if(same_mem(cpuid + 1, AMD_CPUID, 3)) + { + CALL_CPUID(0x80000005, cpuid); + return get_byte(3, cpuid[2]); + } + else + return 32; // default cache line guess + } + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +bool altivec_check_sysctl() + { +#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + int sels[2] = { CTL_MACHDEP, CPU_ALTIVEC }; +#else + // From Apple's docs + int sels[2] = { CTL_HW, HW_VECTORUNIT }; +#endif + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return true; +#endif + + return false; + } + +bool altivec_check_pvr_emul() + { + bool altivec_capable = false; + +#if defined(BOTAN_TARGET_OS_IS_LINUX) || defined(BOTAN_TARGET_OS_IS_NETBSD) + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + + PVR identifiers for various AltiVec enabled CPUs. Taken from + PearPC and Linux sources, mostly. + */ + + const u16bit PVR_G4_7400 = 0x000C; + const u16bit PVR_G5_970 = 0x0039; + const u16bit PVR_G5_970FX = 0x003C; + const u16bit PVR_G5_970MP = 0x0044; + const u16bit PVR_G5_970GX = 0x0045; + const u16bit PVR_POWER6 = 0x003E; + const u16bit PVR_POWER7 = 0x003F; + const u16bit PVR_CELL_PPU = 0x0070; + + // Motorola produced G4s with PVR 0x800[0123C] (at least) + const u16bit PVR_G4_74xx_24 = 0x800; + + u32bit pvr = 0; + + asm volatile("mfspr %0, 287" : "=r" (pvr)); + + // Top 16 bit suffice to identify model + pvr >>= 16; + + altivec_capable |= (pvr == PVR_G4_7400); + altivec_capable |= ((pvr >> 4) == PVR_G4_74xx_24); + altivec_capable |= (pvr == PVR_G5_970); + altivec_capable |= (pvr == PVR_G5_970FX); + altivec_capable |= (pvr == PVR_G5_970MP); + altivec_capable |= (pvr == PVR_G5_970GX); + altivec_capable |= (pvr == PVR_POWER6); + altivec_capable |= (pvr == PVR_POWER7); + altivec_capable |= (pvr == PVR_CELL_PPU); +#endif + + return altivec_capable; + } + +#endif + +} + +void CPUID::initialize() + { + u32bit cpuid[4] = { 0 }; + CALL_CPUID(1, cpuid); + + x86_processor_flags = (static_cast(cpuid[2]) << 32) | cpuid[3]; + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + /* + * If we don't have access to CPUID, we can still safely assume that + * any x86-64 processor has SSE2. + */ + if(x86_processor_flags == 0) + x86_processor_flags |= (1 << CPUID_SSE2_BIT); +#endif + + cache_line = get_x86_cache_line_size(); + + altivec_capable = false; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(altivec_check_sysctl() || altivec_check_pvr_emul()) + altivec_capable = true; +#endif + } + +} +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Default Matcher transform operation (identity) +*/ +std::pair +Data_Store::Matcher::transform(const std::string& key, + const std::string& value) const + { + return std::make_pair(key, value); + } + +/* +* Data_Store Equality Comparison +*/ +bool Data_Store::operator==(const Data_Store& other) const + { + return (contents == other.contents); + } + +/* +* Check if this key has at least one value +*/ +bool Data_Store::has_value(const std::string& key) const + { + return (contents.lower_bound(key) != contents.end()); + } + +/* +* Search based on an arbitrary predicate +*/ +std::multimap +Data_Store::search_with(const Matcher& matcher) const + { + std::multimap out; + + std::multimap::const_iterator i = + contents.begin(); + + while(i != contents.end()) + { + if(matcher(i->first, i->second)) + { + std::pair p( + matcher.transform(i->first, i->second)); + + multimap_insert(out, p.first, p.second); + } + + ++i; + } + + return out; + } + +/* +* Search based on key equality +*/ +std::vector Data_Store::get(const std::string& looking_for) const + { + typedef std::multimap::const_iterator iter; + + std::pair range = contents.equal_range(looking_for); + + std::vector out; + for(iter i = range.first; i != range.second; ++i) + out.push_back(i->second); + return out; + } + +/* +* Get a single atom +*/ +std::string Data_Store::get1(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + throw Invalid_State("Data_Store::get1: Not values for " + key); + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + return vals[0]; + } + +/* +* Get a single MemoryVector atom +*/ +MemoryVector +Data_Store::get1_memvec(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + return MemoryVector(); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + + key); + + return hex_decode(vals[0]); + } + +/* +* Get a single u32bit atom +*/ +u32bit Data_Store::get1_u32bit(const std::string& key, + u32bit default_val) const + { + std::vector vals = get(key); + + if(vals.empty()) + return default_val; + else if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_u32bit: Multiple values for " + + key); + + return to_u32bit(vals[0]); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const std::string& val) + { + multimap_insert(contents, key, val); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, u32bit val) + { + add(key, to_string(val)); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const MemoryRegion& val) + { + add(key, hex_encode(&val[0], val.size())); + } + +/* +* Insert a mapping of key/value pairs +*/ +void Data_Store::add(const std::multimap& in) + { + std::multimap::const_iterator i = in.begin(); + while(i != in.end()) + { + contents.insert(*i); + ++i; + } + } + +} +/** +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + #include +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + #include +#endif + +namespace Botan { + +namespace { + +void raise_runtime_loader_exception(const std::string& lib_name, + const char* msg) + { + throw std::runtime_error("Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error")); + } + +} + +Dynamically_Loaded_Library::Dynamically_Loaded_Library( + const std::string& library) : + lib_name(library), lib(0) + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + lib = ::dlopen(lib_name.c_str(), RTLD_LAZY); + + if(!lib) + raise_runtime_loader_exception(lib_name, dlerror()); + +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + lib = ::LoadLibraryA(lib_name.c_str()); + + if(!lib) + raise_runtime_loader_exception(lib_name, "LoadLibrary failed"); +#endif + + if(!lib) + raise_runtime_loader_exception(lib_name, "Dynamic load not supported"); + } + +Dynamically_Loaded_Library::~Dynamically_Loaded_Library() + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + ::dlclose(lib); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + ::FreeLibrary((HMODULE)lib); +#endif + } + +void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) + { + void* addr = 0; + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + addr = ::dlsym(lib, symbol.c_str()); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + addr = reinterpret_cast(::GetProcAddress((HMODULE)lib, + symbol.c_str())); +#endif + + if(!addr) + throw std::runtime_error("Failed to resolve symbol " + symbol + + " in " + lib_name); + + return addr; + } + +} +/* +* Memory Locking Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK) + #include +#endif + +namespace Botan { + +bool has_mlock() + { + byte buf[4096]; + if(!lock_mem(&buf, sizeof(buf))) + return false; + unlock_mem(&buf, sizeof(buf)); + return true; + } + +/* +* Lock an area of memory into RAM +*/ +bool lock_mem(void* ptr, size_t bytes) + { + Q_UNUSED(ptr); + Q_UNUSED(bytes); +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + return (::mlock(static_cast(ptr), bytes) == 0); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK) + return (::VirtualLock(ptr, bytes) != 0); +#else + return false; +#endif + } + +/* +* Unlock a previously locked region of memory +*/ +void unlock_mem(void* ptr, size_t bytes) + { + Q_UNUSED(ptr); + Q_UNUSED(bytes); +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + ::munlock(static_cast(ptr), bytes); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK) + ::VirtualUnlock(ptr, bytes); +#endif + } + +} +/* +* Parser Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Convert a string into an integer +*/ +u32bit to_u32bit(const std::string& number) + { + u32bit n = 0; + + for(std::string::const_iterator i = number.begin(); i != number.end(); ++i) + { + const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10; + + if(*i == ' ') + continue; + + byte digit = Charset::char2digit(*i); + + if((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5)) + throw Decoding_Error("to_u32bit: Integer overflow"); + n *= 10; + n += digit; + } + return n; + } + +/* +* Convert an integer into a string +*/ +std::string to_string(u64bit n, size_t min_len) + { + std::string lenstr; + if(n) + { + while(n > 0) + { + lenstr = Charset::digit2char(n % 10) + lenstr; + n /= 10; + } + } + else + lenstr = "0"; + + while(lenstr.size() < min_len) + lenstr = "0" + lenstr; + + return lenstr; + } + +/* +* Convert a string into a time duration +*/ +u32bit timespec_to_u32bit(const std::string& timespec) + { + if(timespec == "") + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + u32bit scale = 1; + + if(Charset::is_digit(suffix)) + value += suffix; + else if(suffix == 's') + scale = 1; + else if(suffix == 'm') + scale = 60; + else if(suffix == 'h') + scale = 60 * 60; + else if(suffix == 'd') + scale = 24 * 60 * 60; + else if(suffix == 'y') + scale = 365 * 24 * 60 * 60; + else + throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); + + return scale * to_u32bit(value); + } + +/* +* Parse a SCAN-style algorithm name +*/ +std::vector parse_algorithm_name(const std::string& namex) + { + if(namex.find('(') == std::string::npos && + namex.find(')') == std::string::npos) + return std::vector(1, namex); + + std::string name = namex, substring; + std::vector elems; + size_t level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(std::string::const_iterator i = name.begin(); i != name.end(); ++i) + { + char c = *i; + + if(c == '(') + ++level; + if(c == ')') + { + if(level == 1 && i == name.end() - 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if(level == 0 || (level == 1 && i != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if(c == ',' && level == 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } + else + substring += c; + } + + if(substring != "") + throw Invalid_Algorithm_Name(namex); + + return elems; + } + +/* +* Split the string on slashes +*/ +std::vector split_on(const std::string& str, char delim) + { + std::vector elems; + if(str == "") return elems; + + std::string substr; + for(std::string::const_iterator i = str.begin(); i != str.end(); ++i) + { + if(*i == delim) + { + if(substr != "") + elems.push_back(substr); + substr.clear(); + } + else + substr += *i; + } + + if(substr == "") + throw Invalid_Argument("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/* +* Parse an ASN.1 OID string +*/ +std::vector parse_asn1_oid(const std::string& oid) + { + std::string substring; + std::vector oid_elems; + + for(std::string::const_iterator i = oid.begin(); i != oid.end(); ++i) + { + char c = *i; + + if(c == '.') + { + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring.clear(); + } + else + substring += c; + } + + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + + if(oid_elems.size() < 2) + throw Invalid_OID(oid); + + return oid_elems; + } + +/* +* X.500 String Comparison +*/ +bool x500_name_cmp(const std::string& name1, const std::string& name2) + { + std::string::const_iterator p1 = name1.begin(); + std::string::const_iterator p2 = name2.begin(); + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(Charset::is_space(*p1)) + { + if(!Charset::is_space(*p2)) + return false; + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + } + + if(!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/* +* Convert a decimal-dotted string to binary IP +*/ +u32bit string_to_ipv4(const std::string& str) + { + std::vector parts = split_on(str, '.'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid IP string " + str); + + u32bit ip = 0; + + for(size_t i = 0; i != parts.size(); ++i) + { + u32bit octet = to_u32bit(parts[i]); + + if(octet > 255) + throw Decoding_Error("Invalid IP string " + str); + + ip = (ip << 8) | (octet & 0xFF); + } + + return ip; + } + +/* +* Convert an IP address to decimal-dotted string +*/ +std::string ipv4_to_string(u32bit ip) + { + std::string str; + + for(size_t i = 0; i != sizeof(ip); ++i) + { + if(i) + str += "."; + str += to_string(get_byte(i, ip)); + } + + return str; + } + +} +/* +* Time Functions +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +#if defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + + #ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309 + #endif + + #include + + #ifndef CLOCK_REALTIME + #define CLOCK_REALTIME 0 + #endif + +#endif + +namespace Botan { + +namespace { + +/* +* Combine a two time values into a single one +*/ +u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz) + { + static const u64bit NANOSECONDS_UNITS = 1000000000; + + u64bit res = seconds * NANOSECONDS_UNITS; + res += parts * (NANOSECONDS_UNITS / parts_hz); + return res; + } + +std::tm do_gmtime(time_t time_val) + { + std::tm tm; + +#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S) + gmtime_s(&tm, &time_val); // Windows +#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R) + gmtime_r(&time_val, &tm); // Unix/SUSv2 +#else + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == 0) + throw Encoding_Error("time_t_to_tm could not convert"); + tm = *tm_p; +#endif + + return tm; + } + +} + +/* +* Get the system clock +*/ +u64bit system_time() + { + return static_cast(std::time(0)); + } + +/* +* Convert a time_point to a calendar_point +*/ +calendar_point calendar_value(u64bit a_time_t) + { + std::tm tm = do_gmtime(static_cast(a_time_t)); + + return calendar_point(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + } + +u64bit get_nanoseconds_clock() + { +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + + struct ::timespec tv; + ::clock_gettime(CLOCK_REALTIME, &tv); + return combine_timers(tv.tv_sec, tv.tv_nsec, 1000000000); + +#elif defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY) + + struct ::timeval tv; + ::gettimeofday(&tv, 0); + return combine_timers(tv.tv_sec, tv.tv_usec, 1000000); + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME) + + // Returns time since January 1, 1601 in 100-ns increments + ::FILETIME tv; + ::GetSystemTimeAsFileTime(&tv); + u64bit tstamp = (static_cast(tv.dwHighDateTime) << 32) | + tv.dwLowDateTime; + + return (tstamp * 100); // Scale to 1 nanosecond units + +#else + + return combine_timers(static_cast(std::time(0)), + std::clock(), CLOCKS_PER_SEC); + +#endif + } + +} +/* +* User Interface +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + + +namespace Botan { + +/* +* Get a passphrase from the user +*/ +std::string User_Interface::get_passphrase(const std::string&, + const std::string&, + UI_Result& action) const + { + action = OK; + + if(!first_try) + action = CANCEL_ACTION; + + return preset_passphrase; + } + +/* +* User_Interface Constructor +*/ +User_Interface::User_Interface(const std::string& preset) : + preset_passphrase(preset) + { + first_try = true; + } + +} +/* +* Version Information +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/* + These are intentionally compiled rather than inlined, so an + application running against a shared library can test the true + version they are running against. +*/ + +/* +* Return the version as a string +*/ +std::string version_string() + { + std::ostringstream out; + + out << "Botan " << version_major() << "." + << version_minor() << "." + << version_patch() << " ("; + + if(BOTAN_VERSION_DATESTAMP == 0) + out << "unreleased version"; + else + out << "released " << version_datestamp(); + + out << ", revision " << BOTAN_VERSION_VC_REVISION; + out << ", distribution " << BOTAN_DISTRIBUTION_INFO << ")"; + + return out.str(); + } + +u32bit version_datestamp() { return BOTAN_VERSION_DATESTAMP; } + +/* +* Return parts of the version as integers +*/ +u32bit version_major() { return BOTAN_VERSION_MAJOR; } +u32bit version_minor() { return BOTAN_VERSION_MINOR; } +u32bit version_patch() { return BOTAN_VERSION_PATCH; } + +} diff --git a/client/3rd/QtSsh/src/botan/botan.h b/client/3rd/QtSsh/src/botan/botan.h new file mode 100644 index 00000000..0cdc592f --- /dev/null +++ b/client/3rd/QtSsh/src/botan/botan.h @@ -0,0 +1,16210 @@ +/* +* Botan 1.10.2 Amalgamation +* (C) 1999-2011 Jack Lloyd and others +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AMALGAMATION_H__ +#define BOTAN_AMALGAMATION_H__ + +#ifdef USE_SYSTEM_BOTAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOTAN_VERSION_MAJOR 1 +#define BOTAN_VERSION_MINOR 10 +#define BOTAN_VERSION_PATCH 2 +#define BOTAN_VERSION_DATESTAMP 0 + +#define BOTAN_VERSION_VC_REVISION "mtn:2bf8ad2c501213efb4cf9b219330b87666988e91" + +#define BOTAN_DISTRIBUTION_INFO "unspecified" + +//#ifndef BOTAN_DLL +//#define BOTAN_DLL Q_DECL_IMPORT +//#endif + +#define BOTAN_DLL + +/* Chunk sizes */ +#define BOTAN_DEFAULT_BUFFER_SIZE 4096 +#define BOTAN_MEM_POOL_CHUNK_SIZE 64*1024 +#define BOTAN_BLOCK_CIPHER_PAR_MULT 4 + +/* BigInt toggles */ +#define BOTAN_MP_WORD_BITS 32 +#define BOTAN_KARAT_MUL_THRESHOLD 32 +#define BOTAN_KARAT_SQR_THRESHOLD 32 + +/* PK key consistency checking toggles */ +#define BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD 1 +#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD 0 +#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1 + +/* Should we use GCC-style inline assembler? */ +#if !defined(BOTAN_USE_GCC_INLINE_ASM) && defined(__GNUG__) + #define BOTAN_USE_GCC_INLINE_ASM 1 +#endif + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #define BOTAN_USE_GCC_INLINE_ASM 0 +#endif + +#ifdef __GNUC__ + #define BOTAN_GCC_VERSION \ + (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__) +#else + #define BOTAN_GCC_VERSION 0 +#endif + +#define BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN +#define BOTAN_TARGET_CPU_IS_X86_FAMILY +#define BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK 1 + +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) || \ + defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + #define BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS +#endif + +#if defined(_MSC_VER) + // 4250: inherits via dominance (diamond inheritence issue) + // 4251: needs DLL interface (STL DLL exports) + #pragma warning(disable: 4250 4251) +#endif + +/* +* Compile-time deprecatation warnings +*/ +#if !defined(BOTAN_NO_DEPRECATED_WARNINGS) + + #if defined(__clang__) + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) + + #elif defined(_MSC_VER) + #define BOTAN_DEPRECATED(msg) __declspec(deprecated(msg)) + + #elif defined(__GNUG__) + + #if BOTAN_GCC_VERSION >= 450 && !defined(__INTEL_COMPILER) + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) + #else + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) + #endif + + #endif + +#endif + +#if !defined(BOTAN_DEPRECATED) + #define BOTAN_DEPRECATED(msg) +#endif + +/* +* Module availability definitions +*/ +#define BOTAN_HAS_ADLER32 +#define BOTAN_HAS_AES +#define BOTAN_HAS_ALGORITHM_FACTORY +#define BOTAN_HAS_ANSI_X919_MAC +#define BOTAN_HAS_ARC4 +#define BOTAN_HAS_ASN1 +#define BOTAN_HAS_AUTO_SEEDING_RNG +#define BOTAN_HAS_BASE64_CODEC +#define BOTAN_HAS_BCRYPT +#define BOTAN_HAS_BIGINT +#define BOTAN_HAS_BIGINT_MATH +#define BOTAN_HAS_BIGINT_MP +#define BOTAN_HAS_BLOCK_CIPHER +#define BOTAN_HAS_BLOWFISH +#define BOTAN_HAS_BMW_512 +#define BOTAN_HAS_CAMELLIA +#define BOTAN_HAS_CASCADE +#define BOTAN_HAS_CAST +#define BOTAN_HAS_CBC +#define BOTAN_HAS_CBC_MAC +#define BOTAN_HAS_CERTIFICATE_STORE +#define BOTAN_HAS_CFB +#define BOTAN_HAS_CIPHER_MODE_PADDING +#define BOTAN_HAS_CMAC +#define BOTAN_HAS_CODEC_FILTERS +#define BOTAN_HAS_COMB4P +#define BOTAN_HAS_CORE_ENGINE +#define BOTAN_HAS_CRC24 +#define BOTAN_HAS_CRC32 +#define BOTAN_HAS_CRYPTO_BOX +#define BOTAN_HAS_CTR_BE +#define BOTAN_HAS_CTS +#define BOTAN_HAS_DES +#define BOTAN_HAS_DIFFIE_HELLMAN +#define BOTAN_HAS_DLIES +#define BOTAN_HAS_DL_GROUP +#define BOTAN_HAS_DL_PUBLIC_KEY_FAMILY +#define BOTAN_HAS_DSA +#define BOTAN_HAS_EAX +#define BOTAN_HAS_ECB +#define BOTAN_HAS_ECC_GROUP +#define BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO +#define BOTAN_HAS_ECDH +#define BOTAN_HAS_ECDSA +#define BOTAN_HAS_EC_CURVE_GFP +#define BOTAN_HAS_ELGAMAL +#define BOTAN_HAS_EME1 +#define BOTAN_HAS_EME_PKCS1v15 +#define BOTAN_HAS_EMSA1 +#define BOTAN_HAS_EMSA1_BSI +#define BOTAN_HAS_EMSA2 +#define BOTAN_HAS_EMSA3 +#define BOTAN_HAS_EMSA4 +#define BOTAN_HAS_EMSA_RAW +#define BOTAN_HAS_ENGINES +#define BOTAN_HAS_ENGINE_SIMD +#define BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER +#define BOTAN_HAS_FILTERS +#define BOTAN_HAS_FPE_FE1 +#define BOTAN_HAS_GOST_28147_89 +#define BOTAN_HAS_GOST_34_10_2001 +#define BOTAN_HAS_GOST_34_11 +#define BOTAN_HAS_HASH_ID +#define BOTAN_HAS_HAS_160 +#define BOTAN_HAS_HEX_CODEC +#define BOTAN_HAS_HMAC +#define BOTAN_HAS_HMAC_RNG +#define BOTAN_HAS_IDEA +#define BOTAN_HAS_IF_PUBLIC_KEY_FAMILY +#define BOTAN_HAS_KASUMI +#define BOTAN_HAS_KDF1 +#define BOTAN_HAS_KDF2 +#define BOTAN_HAS_KDF_BASE +#define BOTAN_HAS_KECCAK +#define BOTAN_HAS_KEYPAIR_TESTING +#define BOTAN_HAS_LIBSTATE_MODULE +#define BOTAN_HAS_LION +#define BOTAN_HAS_LUBY_RACKOFF +#define BOTAN_HAS_MARS +#define BOTAN_HAS_MD2 +#define BOTAN_HAS_MD4 +#define BOTAN_HAS_MD5 +#define BOTAN_HAS_MDX_HASH_FUNCTION +#define BOTAN_HAS_MGF1 +#define BOTAN_HAS_MISTY1 +#define BOTAN_HAS_MUTEX_NOOP +#define BOTAN_HAS_MUTEX_WRAPPERS +#define BOTAN_HAS_NOEKEON +#define BOTAN_HAS_NOEKEON_SIMD +#define BOTAN_HAS_NYBERG_RUEPPEL +#define BOTAN_HAS_OFB +#define BOTAN_HAS_OID_LOOKUP +#define BOTAN_HAS_OPENPGP_CODEC +#define BOTAN_HAS_PACKAGE_TRANSFORM +#define BOTAN_HAS_PARALLEL_HASH +#define BOTAN_HAS_PASSHASH9 +#define BOTAN_HAS_PASSWORD_BASED_ENCRYPTION +#define BOTAN_HAS_PBE_PKCS_V15 +#define BOTAN_HAS_PBE_PKCS_V20 +#define BOTAN_HAS_PBKDF1 +#define BOTAN_HAS_PBKDF2 +#define BOTAN_HAS_PEM_CODEC +#define BOTAN_HAS_PGPS2K +#define BOTAN_HAS_PKCS10_REQUESTS +#define BOTAN_HAS_PK_PADDING +#define BOTAN_HAS_PUBLIC_KEY_CRYPTO +#define BOTAN_HAS_PUBLIC_KEY_CRYPTO +#define BOTAN_HAS_RANDPOOL +#define BOTAN_HAS_RC2 +#define BOTAN_HAS_RC5 +#define BOTAN_HAS_RC6 +#define BOTAN_HAS_RFC3394_KEYWRAP +#define BOTAN_HAS_RIPEMD_128 +#define BOTAN_HAS_RIPEMD_160 +#define BOTAN_HAS_RSA +#define BOTAN_HAS_RUNTIME_BENCHMARKING +#define BOTAN_HAS_RW +#define BOTAN_HAS_SAFER +#define BOTAN_HAS_SALSA20 +#define BOTAN_HAS_SEED +#define BOTAN_HAS_SELFTESTS +#define BOTAN_HAS_SERPENT +#define BOTAN_HAS_SERPENT_SIMD +#define BOTAN_HAS_SHA1 +#define BOTAN_HAS_SHA2_32 +#define BOTAN_HAS_SHA2_64 +#define BOTAN_HAS_SIMD_32 +#define BOTAN_HAS_SIMD_SCALAR +#define BOTAN_HAS_SKEIN_512 +#define BOTAN_HAS_SKIPJACK +#define BOTAN_HAS_SQUARE +#define BOTAN_HAS_SRP6 +#define BOTAN_HAS_SSL3_MAC +#define BOTAN_HAS_SSL_V3_PRF +#define BOTAN_HAS_STREAM_CIPHER +#define BOTAN_HAS_TEA +#define BOTAN_HAS_THRESHOLD_SECRET_SHARING +#define BOTAN_HAS_TIGER +#define BOTAN_HAS_TLS_V10_PRF +#define BOTAN_HAS_TURING +#define BOTAN_HAS_TWOFISH +#define BOTAN_HAS_UTIL_FUNCTIONS +#define BOTAN_HAS_WHIRLPOOL +#define BOTAN_HAS_WID_WAKE +#define BOTAN_HAS_X509_CA +#define BOTAN_HAS_X509_CERTIFICATES +#define BOTAN_HAS_X509_CRL +#define BOTAN_HAS_X509_SELF_SIGNED +#define BOTAN_HAS_X509_STORE +#define BOTAN_HAS_X931_RNG +#define BOTAN_HAS_X942_PRF +#define BOTAN_HAS_XTEA +#define BOTAN_HAS_XTEA_SIMD +#define BOTAN_HAS_XTS + +/* +* Local configuration options (if any) follow +*/ + + +#include + +/** +* The primary namespace for the botan library +*/ +namespace Botan { + +/** +* Typedef representing an unsigned 8-bit quantity +*/ +typedef unsigned char byte; + +/** +* Typedef representing an unsigned 16-bit quantity +*/ +typedef unsigned short u16bit; + +/** +* Typedef representing an unsigned 32-bit quantity +*/ +typedef unsigned int u32bit; + +/** +* Typedef representing a signed 32-bit quantity +*/ +typedef signed int s32bit; + +/** +* Typedef representing an unsigned 64-bit quantity +*/ +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned __int64 u64bit; +#elif defined(__KCC) + typedef unsigned __long_long u64bit; +#elif defined(__GNUG__) + __extension__ typedef unsigned long long u64bit; +#else + typedef unsigned long long u64bit; +#endif + +/** +* A default buffer size; typically a memory page +*/ +static const size_t DEFAULT_BUFFERSIZE = BOTAN_DEFAULT_BUFFER_SIZE; + +} + +namespace Botan_types { + +using Botan::byte; +using Botan::u32bit; + +} + + +namespace Botan { + +/** +* Allocator Interface +*/ +class BOTAN_DLL Allocator + { + public: + /** + * Acquire a pointer to an allocator + * @param locking is true if the allocator should attempt to + * secure the memory (eg for using to store keys) + * @return pointer to an allocator; ownership remains with library, + * so do not delete + */ + static Allocator* get(bool locking); + + /** + * Allocate a block of memory + * @param n how many bytes to allocate + * @return pointer to n bytes of memory + */ + virtual void* allocate(size_t n) = 0; + + /** + * Deallocate memory allocated with allocate() + * @param ptr the pointer returned by allocate() + * @param n the size of the block pointed to by ptr + */ + virtual void deallocate(void* ptr, size_t n) = 0; + + /** + * @return name of this allocator type + */ + virtual std::string type() const = 0; + + /** + * Initialize the allocator + */ + virtual void init() {} + + /** + * Shutdown the allocator + */ + virtual void destroy() {} + + virtual ~Allocator() Q_DECL_NOEXCEPT_EXPR(false) {} + }; + +} + + +namespace Botan { + +/** +* Copy memory +* @param out the destination array +* @param in the source array +* @param n the number of elements of in/out +*/ +template inline void copy_mem(T* out, const T* in, size_t n) + { + std::memmove(out, in, sizeof(T)*n); + } + +/** +* Zeroize memory +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +*/ +template inline void clear_mem(T* ptr, size_t n) + { + if(n) // avoid glibc warning if n == 0 + std::memset(ptr, 0, sizeof(T)*n); + } + +/** +* Set memory to a fixed value +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +* @param val the value to set each byte to +*/ +template +inline void set_mem(T* ptr, size_t n, byte val) + { + std::memset(ptr, val, sizeof(T)*n); + } + +/** +* Memory comparison, input insensitive +* @param p1 a pointer to an array +* @param p2 a pointer to another array +* @param n the number of Ts in p1 and p2 +* @return true iff p1[i] == p2[i] forall i in [0...n) +*/ +template inline bool same_mem(const T* p1, const T* p2, size_t n) + { + bool is_same = true; + + for(size_t i = 0; i != n; ++i) + is_same &= (p1[i] == p2[i]); + + return is_same; + } + +} + + +namespace Botan { + +/** +* This class represents variable length memory buffers. +*/ +template +class MemoryRegion + { + public: + /** + * Find out the size of the buffer, i.e. how many objects of type T it + * contains. + * @return size of the buffer + */ + size_t size() const { return used; } + + /** + * Find out whether this buffer is empty. + * @return true if the buffer is empty, false otherwise + */ + bool empty() const { return (used == 0); } + + /** + * Get a pointer to the first element in the buffer. + * @return pointer to the first element in the buffer + */ + operator T* () { return buf; } + + /** + * Get a constant pointer to the first element in the buffer. + * @return constant pointer to the first element in the buffer + */ + operator const T* () const { return buf; } + + /** + * Get a pointer to the first element in the buffer. + * @return pointer to the first element in the buffer + */ + T* begin() { return buf; } + + /** + * Get a constant pointer to the first element in the buffer. + * @return constant pointer to the first element in the buffer + */ + const T* begin() const { return buf; } + + /** + * Get a pointer to one past the last element in the buffer. + * @return pointer to one past the last element in the buffer + */ + T* end() { return (buf + size()); } + + /** + * Get a const pointer to one past the last element in the buffer. + * @return const pointer to one past the last element in the buffer + */ + const T* end() const { return (buf + size()); } + + /** + * Check two buffers for equality. + * @return true iff the content of both buffers is byte-wise equal + */ + bool operator==(const MemoryRegion& other) const + { + return (size() == other.size() && + same_mem(buf, other.buf, size())); + } + + /** + * Compare two buffers + * @return true iff this is ordered before other + */ + bool operator<(const MemoryRegion& other) const; + + /** + * Check two buffers for inequality. + * @return false if the content of both buffers is byte-wise equal, true + * otherwise. + */ + bool operator!=(const MemoryRegion& other) const + { return (!(*this == other)); } + + /** + * Copy the contents of another buffer into this buffer. + * The former contents of *this are discarded. + * @param other the buffer to copy the contents from. + * @return reference to *this + */ + MemoryRegion& operator=(const MemoryRegion& other) + { + if(this != &other) + { + this->resize(other.size()); + this->copy(&other[0], other.size()); + } + return (*this); + } + + /** + * Copy the contents of an array of objects of type T into this buffer. + * The former contents of *this are discarded. + * The length of *this must be at least n, otherwise memory errors occur. + * @param in the array to copy the contents from + * @param n the length of in + */ + void copy(const T in[], size_t n) + { + copy_mem(buf, in, std::min(n, size())); + } + + /** + * Copy the contents of an array of objects of type T into this buffer. + * The former contents of *this are discarded. + * The length of *this must be at least n, otherwise memory errors occur. + * @param off the offset position inside this buffer to start inserting + * the copied bytes + * @param in the array to copy the contents from + * @param n the length of in + */ + void copy(size_t off, const T in[], size_t n) + { + copy_mem(buf + off, in, std::min(n, size() - off)); + } + + /** + * Append a single element. + * @param x the element to append + */ + void push_back(T x) + { + resize(size() + 1); + buf[size()-1] = x; + } + + /** + * Reset this buffer to an empty buffer with size zero. + */ + void clear() { resize(0); } + + /** + * Inserts or erases elements at the end such that the size + * becomes n, leaving elements in the range 0...n unmodified if + * set or otherwise zero-initialized + * @param n length of the new buffer + */ + void resize(size_t n); + + /** + * Swap this buffer with another object. + */ + void swap(MemoryRegion& other); + + virtual ~MemoryRegion() { deallocate(buf, allocated); } + protected: + MemoryRegion() : buf(0), used(0), allocated(0), alloc(0) {} + + /** + * Copy constructor + * @param other the other region to copy + */ + MemoryRegion(const MemoryRegion& other) : + buf(0), + used(0), + allocated(0), + alloc(other.alloc) + { + resize(other.size()); + copy(&other[0], other.size()); + } + + /** + * @param locking should we use a locking allocator + * @param length the initial length to use + */ + void init(bool locking, size_t length = 0) + { alloc = Allocator::get(locking); resize(length); } + + private: + T* allocate(size_t n) + { + return static_cast(alloc->allocate(sizeof(T)*n)); + } + + void deallocate(T* p, size_t n) + { if(alloc && p && n) alloc->deallocate(p, sizeof(T)*n); } + + T* buf; + size_t used; + size_t allocated; + Allocator* alloc; + }; + +/* +* Change the size of the buffer +*/ +template +void MemoryRegion::resize(size_t n) + { + if(n <= allocated) + { + size_t zap = std::min(used, n); + clear_mem(buf + zap, allocated - zap); + used = n; + } + else + { + T* new_buf = allocate(n); + copy_mem(new_buf, buf, used); + deallocate(buf, allocated); + buf = new_buf; + allocated = used = n; + } + } + +/* +* Compare this buffer with another one +*/ +template +bool MemoryRegion::operator<(const MemoryRegion& other) const + { + const size_t min_size = std::min(size(), other.size()); + + // This should probably be rewritten to run in constant time + for(size_t i = 0; i != min_size; ++i) + { + if(buf[i] < other[i]) + return true; + if(buf[i] > other[i]) + return false; + } + + // First min_size bytes are equal, shorter is first + return (size() < other.size()); + } + +/* +* Swap this buffer with another one +*/ +template +void MemoryRegion::swap(MemoryRegion& x) + { + std::swap(buf, x.buf); + std::swap(used, x.used); + std::swap(allocated, x.allocated); + std::swap(alloc, x.alloc); + } + +/** +* This class represents variable length buffers that do not +* make use of memory locking. +*/ +template +class MemoryVector : public MemoryRegion + { + public: + /** + * Copy the contents of another buffer into this buffer. + * @param in the buffer to copy the contents from + * @return reference to *this + */ + MemoryVector& operator=(const MemoryRegion& in) + { + if(this != &in) + { + this->resize(in.size()); + this->copy(&in[0], in.size()); + } + return (*this); + } + + /** + * Create a buffer of the specified length. + * @param n the length of the buffer to create. + */ + MemoryVector(size_t n = 0) { this->init(false, n); } + + /** + * Create a buffer with the specified contents. + * @param in the array containing the data to be initially copied + * into the newly created buffer + * @param n the size of the arry in + */ + MemoryVector(const T in[], size_t n) + { + this->init(false); + this->resize(n); + this->copy(in, n); + } + + /** + * Copy constructor. + */ + MemoryVector(const MemoryRegion& in) + { + this->init(false); + this->resize(in.size()); + this->copy(&in[0], in.size()); + } + }; + +/** +* This class represents variable length buffers using the operating +* systems capability to lock memory, i.e. keeping it from being +* swapped out to disk. In this way, a security hole allowing attackers +* to find swapped out secret keys is closed. +*/ +template +class SecureVector : public MemoryRegion + { + public: + /** + * Copy the contents of another buffer into this buffer. + * @param other the buffer to copy the contents from + * @return reference to *this + */ + SecureVector& operator=(const MemoryRegion& other) + { + if(this != &other) + { + this->resize(other.size()); + this->copy(&other[0], other.size()); + } + return (*this); + } + + /** + * Create a buffer of the specified length. + * @param n the length of the buffer to create. + */ + SecureVector(size_t n = 0) { this->init(true, n); } + + /** + * Create a buffer with the specified contents. + * @param in the array containing the data to be initially copied + * into the newly created buffer + * @param n the size of the array in + */ + SecureVector(const T in[], size_t n) + { + this->init(true); + this->resize(n); + this->copy(&in[0], n); + } + + /** + * Create a buffer with contents specified contents. + * @param in the buffer holding the contents that will be + * copied into the newly created buffer. + */ + SecureVector(const MemoryRegion& in) + { + this->init(true); + this->resize(in.size()); + this->copy(&in[0], in.size()); + } + }; + +template +MemoryRegion& operator+=(MemoryRegion& out, + const MemoryRegion& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.size()); + copy_mem(&out[copy_offset], &in[0], in.size()); + return out; + } + +template +MemoryRegion& operator+=(MemoryRegion& out, + T in) + { + out.push_back(in); + return out; + } + +template +MemoryRegion& operator+=(MemoryRegion& out, + const std::pair& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + copy_mem(&out[copy_offset], in.first, in.second); + return out; + } + +template +MemoryRegion& operator+=(MemoryRegion& out, + const std::pair& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + copy_mem(&out[copy_offset], in.first, in.second); + return out; + } + +/** +* Zeroise the values; length remains unchanged +* @param vec the vector to zeroise +*/ +template +void zeroise(MemoryRegion& vec) + { + clear_mem(&vec[0], vec.size()); + } + +} + +namespace std { + +template +inline void swap(Botan::MemoryRegion& x, Botan::MemoryRegion& y) + { + x.swap(y); + } + +} + + +namespace Botan { + +/** +* Byte extraction +* @param byte_num which byte to extract, 0 == highest byte +* @param input the value to extract from +* @return byte byte_num of input +*/ +template inline byte get_byte(size_t byte_num, T input) + { + return static_cast( + input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3) + ); + } + +} + + +namespace Botan { + +/** +* This class represents any kind of computation which uses an internal +* state, such as hash functions or MACs +*/ +class BOTAN_DLL Buffered_Computation + { + public: + /** + * @return length of the output of this function in bytes + */ + virtual size_t output_length() const = 0; + + /** + * Add new input to process. + * @param in the input to process as a byte array + * @param length of param in in bytes + */ + void update(const byte in[], size_t length) { add_data(in, length); } + + /** + * Add new input to process. + * @param in the input to process as a MemoryRegion + */ + void update(const MemoryRegion& in) + { + add_data(&in[0], in.size()); + } + + /** + * Add an integer in big-endian order + * @param in the value + */ + template void update_be(const T in) + { + for(size_t i = 0; i != sizeof(T); ++i) + { + byte b = get_byte(i, in); + add_data(&b, 1); + } + } + + /** + * Add new input to process. + * @param str the input to process as a std::string. Will be interpreted + * as a byte array based on + * the strings encoding. + */ + void update(const std::string& str) + { + add_data(reinterpret_cast(str.data()), str.size()); + } + + /** + * Process a single byte. + * @param in the byte to process + */ + void update(byte in) { add_data(&in, 1); } + + /** + * Complete the computation and retrieve the + * final result. + * @param out The byte array to be filled with the result. + * Must be of length output_length() + */ + void final(byte out[]) { final_result(out); } + + /** + * Complete the computation and retrieve the + * final result. + * @return SecureVector holding the result + */ + SecureVector final() + { + SecureVector output(output_length()); + final_result(&output[0]); + return output; + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a byte array + * @param length the length of the byte array + * @result the result of the call to final() + */ + SecureVector process(const byte in[], size_t length) + { + add_data(in, length); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + SecureVector process(const MemoryRegion& in) + { + add_data(&in[0], in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a string + * @result the result of the call to final() + */ + SecureVector process(const std::string& in) + { + update(in); + return final(); + } + + virtual ~Buffered_Computation() {} + private: + /** + * Add more data to the computation + * @param input is an input buffer + * @param length is the length of input in bytes + */ + virtual void add_data(const byte input[], size_t length) = 0; + + /** + * Write the final output to out + * @param out is an output buffer of output_length() + */ + virtual void final_result(byte out[]) = 0; + }; + +} + + +namespace Botan { + +/** +* Class used to accumulate the poll results of EntropySources +*/ +class BOTAN_DLL Entropy_Accumulator + { + public: + /** + * Initialize an Entropy_Accumulator + * @param goal is how many bits we would like to collect + */ + Entropy_Accumulator(size_t goal) : + entropy_goal(goal), collected_bits(0) {} + + virtual ~Entropy_Accumulator() {} + + /** + * Get a cached I/O buffer (purely for minimizing allocation + * overhead to polls) + * + * @param size requested size for the I/O buffer + * @return cached I/O buffer for repeated polls + */ + MemoryRegion& get_io_buffer(size_t size) + { io_buffer.resize(size); return io_buffer; } + + /** + * @return number of bits collected so far + */ + size_t bits_collected() const + { return static_cast(collected_bits); } + + /** + * @return if our polling goal has been achieved + */ + bool polling_goal_achieved() const + { return (collected_bits >= entropy_goal); } + + /** + * @return how many bits we need to reach our polling goal + */ + size_t desired_remaining_bits() const + { + if(collected_bits >= entropy_goal) + return 0; + return static_cast(entropy_goal - collected_bits); + } + + /** + * Add entropy to the accumulator + * @param bytes the input bytes + * @param length specifies how many bytes the input is + * @param entropy_bits_per_byte is a best guess at how much + * entropy per byte is in this input + */ + void add(const void* bytes, size_t length, double entropy_bits_per_byte) + { + add_bytes(reinterpret_cast(bytes), length); + collected_bits += entropy_bits_per_byte * length; + } + + /** + * Add entropy to the accumulator + * @param v is some value + * @param entropy_bits_per_byte is a best guess at how much + * entropy per byte is in this input + */ + template + void add(const T& v, double entropy_bits_per_byte) + { + add(&v, sizeof(T), entropy_bits_per_byte); + } + private: + virtual void add_bytes(const byte bytes[], size_t length) = 0; + + SecureVector io_buffer; + size_t entropy_goal; + double collected_bits; + }; + +/** +* Entropy accumulator that puts the input into a Buffered_Computation +*/ +class BOTAN_DLL Entropy_Accumulator_BufferedComputation : + public Entropy_Accumulator + { + public: + /** + * @param sink the hash or MAC we are feeding the poll data into + * @param goal is how many bits we want to collect in this poll + */ + Entropy_Accumulator_BufferedComputation(Buffered_Computation& sink, + size_t goal) : + Entropy_Accumulator(goal), entropy_sink(sink) {} + + private: + virtual void add_bytes(const byte bytes[], size_t length) + { + entropy_sink.update(bytes, length); + } + + Buffered_Computation& entropy_sink; + }; + +/** +* Abstract interface to a source of (hopefully unpredictable) system entropy +*/ +class BOTAN_DLL EntropySource + { + public: + /** + * @return name identifying this entropy source + */ + virtual std::string name() const = 0; + + /** + * Perform an entropy gathering poll + * @param accum is an accumulator object that will be given entropy + */ + virtual void poll(Entropy_Accumulator& accum) = 0; + + virtual ~EntropySource() {} + }; + +} + + +namespace Botan { + +/** +* Parse a SCAN-style algorithm name +* @param scan_name the name +* @return the name components +*/ +BOTAN_DLL std::vector +parse_algorithm_name(const std::string& scan_name); + +/** +* Split a string +* @param str the input string +* @param delim the delimitor +* @return string split by delim +*/ +BOTAN_DLL std::vector split_on( + const std::string& str, char delim); + +/** +* Parse an ASN.1 OID +* @param oid the OID in string form +* @return OID components +*/ +BOTAN_DLL std::vector parse_asn1_oid(const std::string& oid); + +/** +* Compare two names using the X.509 comparison algorithm +* @param name1 the first name +* @param name2 the second name +* @return true if name1 is the same as name2 by the X.509 comparison rules +*/ +BOTAN_DLL bool x500_name_cmp(const std::string& name1, + const std::string& name2); + +/** +* Convert a number to a string +* @param n the integer to convert to a string +* @param min_len the min length of the output string +* @return n convert to a string +*/ +BOTAN_DLL std::string to_string(u64bit n, size_t min_len = 0); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_DLL u32bit to_u32bit(const std::string& str); + +/** +* Convert a time specification to a number +* @param timespec the time specification +* @return number of seconds represented by timespec +*/ +BOTAN_DLL u32bit timespec_to_u32bit(const std::string& timespec); + +/** +* Convert a string representation of an IPv4 address to a number +* @param ip_str the string representation +* @return integer IPv4 address +*/ +BOTAN_DLL u32bit string_to_ipv4(const std::string& ip_str); + +/** +* Convert an IPv4 address to a string +* @param ip_addr the IPv4 address to convert +* @return string representation of the IPv4 address +*/ +BOTAN_DLL std::string ipv4_to_string(u32bit ip_addr); + +} + + +namespace Botan { + +typedef std::runtime_error Exception; +typedef std::invalid_argument Invalid_Argument; + +/** +* Invalid_State Exception +*/ +struct BOTAN_DLL Invalid_State : public Exception + { + Invalid_State(const std::string& err) : + Exception(err) + {} + }; + +/** +* Lookup_Error Exception +*/ +struct BOTAN_DLL Lookup_Error : public Exception + { + Lookup_Error(const std::string& err) : + Exception(err) + {} + }; + +/** +* Internal_Error Exception +*/ +struct BOTAN_DLL Internal_Error : public Exception + { + Internal_Error(const std::string& err) : + Exception("Internal error: " + err) + {} + }; + +/** +* Invalid_Key_Length Exception +*/ +struct BOTAN_DLL Invalid_Key_Length : public Invalid_Argument + { + Invalid_Key_Length(const std::string& name, size_t length) : + Invalid_Argument(name + " cannot accept a key of length " + + to_string(length)) + {} + }; + +/** +* Invalid_Block_Size Exception +*/ +struct BOTAN_DLL Invalid_Block_Size : public Invalid_Argument + { + Invalid_Block_Size(const std::string& mode, + const std::string& pad) : + Invalid_Argument("Padding method " + pad + + " cannot be used with " + mode) + {} + }; + +/** +* Invalid_IV_Length Exception +*/ +struct BOTAN_DLL Invalid_IV_Length : public Invalid_Argument + { + Invalid_IV_Length(const std::string& mode, size_t bad_len) : + Invalid_Argument("IV length " + to_string(bad_len) + + " is invalid for " + mode) + {} + }; + +/** +* PRNG_Unseeded Exception +*/ +struct BOTAN_DLL PRNG_Unseeded : public Invalid_State + { + PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) + {} + }; + +/** +* Policy_Violation Exception +*/ +struct BOTAN_DLL Policy_Violation : public Invalid_State + { + Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) + {} + }; + +/** +* Algorithm_Not_Found Exception +*/ +struct BOTAN_DLL Algorithm_Not_Found : public Lookup_Error + { + Algorithm_Not_Found(const std::string& name) : + Lookup_Error("Could not find any algorithm named \"" + name + "\"") + {} + }; + +/** +* Invalid_Algorithm_Name Exception +*/ +struct BOTAN_DLL Invalid_Algorithm_Name : public Invalid_Argument + { + Invalid_Algorithm_Name(const std::string& name): + Invalid_Argument("Invalid algorithm name: " + name) + {} + }; + +/** +* Encoding_Error Exception +*/ +struct BOTAN_DLL Encoding_Error : public Invalid_Argument + { + Encoding_Error(const std::string& name) : + Invalid_Argument("Encoding error: " + name) {} + }; + +/** +* Decoding_Error Exception +*/ +struct BOTAN_DLL Decoding_Error : public Invalid_Argument + { + Decoding_Error(const std::string& name) : + Invalid_Argument("Decoding error: " + name) {} + }; + +/** +* Integrity_Failure Exception +*/ +struct BOTAN_DLL Integrity_Failure : public Exception + { + Integrity_Failure(const std::string& msg) : + Exception("Integrity failure: " + msg) {} + }; + +/** +* Invalid_OID Exception +*/ +struct BOTAN_DLL Invalid_OID : public Decoding_Error + { + Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) {} + }; + +/** +* Stream_IO_Error Exception +*/ +struct BOTAN_DLL Stream_IO_Error : public Exception + { + Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) + {} + }; + +/** +* Self Test Failure Exception +*/ +struct BOTAN_DLL Self_Test_Failure : public Internal_Error + { + Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) + {} + }; + +/** +* Memory Allocation Exception +*/ +struct BOTAN_DLL Memory_Exhaustion : public std::bad_alloc + { + const char* what() const throw() + { return "Ran out of memory, allocation failed"; } + }; + +} + + +namespace Botan { + +/** +* This class represents a random number (RNG) generator object. +*/ +class BOTAN_DLL RandomNumberGenerator + { + public: + /** + * Create a seeded and active RNG object for general application use + */ + static RandomNumberGenerator* make_rng(); + + /** + * Randomize a byte array. + * @param output the byte array to hold the random output. + * @param length the length of the byte array output. + */ + virtual void randomize(byte output[], size_t length) = 0; + + /** + * Return a random vector + * @param bytes number of bytes in the result + * @return randomized vector of length bytes + */ + SecureVector random_vec(size_t bytes) + { + SecureVector output(bytes); + randomize(&output[0], output.size()); + return output; + } + + /** + * Return a random byte + * @return random byte + */ + byte next_byte(); + + /** + * Check whether this RNG is seeded. + * @return true if this RNG was already seeded, false otherwise. + */ + virtual bool is_seeded() const { return true; } + + /** + * Clear all internally held values of this RNG. + */ + virtual void clear() = 0; + + /** + * Return the name of this object + */ + virtual std::string name() const = 0; + + /** + * Seed this RNG using the entropy sources it contains. + * @param bits_to_collect is the number of bits of entropy to + attempt to gather from the entropy sources + */ + virtual void reseed(size_t bits_to_collect) = 0; + + /** + * Add this entropy source to the RNG object + * @param source the entropy source which will be retained and used by RNG + */ + virtual void add_entropy_source(EntropySource* source) = 0; + + /** + * Add entropy to this RNG. + * @param in a byte array containg the entropy to be added + * @param length the length of the byte array in + */ + virtual void add_entropy(const byte in[], size_t length) = 0; + + RandomNumberGenerator() {} + virtual ~RandomNumberGenerator() {} + private: + RandomNumberGenerator(const RandomNumberGenerator&) {} + RandomNumberGenerator& operator=(const RandomNumberGenerator&) + { return (*this); } + }; + +/** +* Null/stub RNG - fails if you try to use it for anything +*/ +class BOTAN_DLL Null_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], size_t) { throw PRNG_Unseeded("Null_RNG"); } + void clear() {} + std::string name() const { return "Null_RNG"; } + + void reseed(size_t) {} + bool is_seeded() const { return false; } + void add_entropy(const byte[], size_t) {} + void add_entropy_source(EntropySource* es) { delete es; } + }; + +} + + +namespace Botan { + +/** +* Encoding Method for Signatures, Appendix +*/ +class BOTAN_DLL EMSA + { + public: + /** + * Add more data to the signature computation + * @param input some data + * @param length length of input in bytes + */ + virtual void update(const byte input[], size_t length) = 0; + + /** + * @return raw hash + */ + virtual SecureVector raw_data() = 0; + + /** + * Return the encoding of a message + * @param msg the result of raw_data() + * @param output_bits the desired output bit size + * @param rng a random number generator + * @return encoded signature + */ + virtual SecureVector encoding_of(const MemoryRegion& msg, + size_t output_bits, + RandomNumberGenerator& rng) = 0; + + /** + * Verify the encoding + * @param coded the received (coded) message representative + * @param raw the computed (local, uncoded) message representative + * @param key_bits the size of the key in bits + * @return true if coded is a valid encoding of raw, otherwise false + */ + virtual bool verify(const MemoryRegion& coded, + const MemoryRegion& raw, + size_t key_bits) = 0; + virtual ~EMSA() {} + }; + +} + + +namespace Botan { + +/** +* This class represents an algorithm of some kind +*/ +class BOTAN_DLL Algorithm + { + public: + + /** + * Zeroize internal state + */ + virtual void clear() = 0; + + /** + * @return name of this algorithm + */ + virtual std::string name() const = 0; + + Algorithm() {} + virtual ~Algorithm() {} + private: + Algorithm(const Algorithm&) {} + Algorithm& operator=(const Algorithm&) { return (*this); } + }; + +} + + +namespace Botan { + +/** +* This class represents hash function (message digest) objects +*/ +class BOTAN_DLL HashFunction : public Buffered_Computation, + public Algorithm + { + public: + /** + * Get a new object representing the same algorithm as *this + */ + virtual HashFunction* clone() const = 0; + + /** + * The hash block size as defined for this algorithm + */ + virtual size_t hash_block_size() const { return 0; } + }; + +} + + +namespace Botan { + +/** +* EMSA1 from IEEE 1363 +* Essentially, sign the hash directly +*/ +class BOTAN_DLL EMSA1 : public EMSA + { + public: + /** + * @param h the hash object to use + */ + EMSA1(HashFunction* h) : hash(h) {} + ~EMSA1() { delete hash; } + protected: + /** + * @return const pointer to the underlying hash + */ + const HashFunction* hash_ptr() const { return hash; } + private: + void update(const byte[], size_t); + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + + HashFunction* hash; + }; + +} + + +namespace Botan { + +/** +* Keccak[1600], a SHA-3 candidate +*/ +class BOTAN_DLL Keccak_1600 : public HashFunction + { + public: + + /** + * @param output_bits the size of the hash output; must be one of + * 224, 256, 384, or 512 + */ + Keccak_1600(size_t output_bits = 512); + + size_t hash_block_size() const { return bitrate / 8; } + size_t output_length() const { return output_bits / 8; } + + HashFunction* clone() const; + std::string name() const; + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + size_t output_bits, bitrate; + SecureVector S; + size_t S_pos; + }; + +} + + +namespace Botan { + +/** +A class encapsulating a SCAN name (similar to JCE conventions) +http://www.users.zetnet.co.uk/hopwood/crypto/scan/ +*/ +class BOTAN_DLL SCAN_Name + { + public: + /** + * @param algo_spec A SCAN-format name + */ + SCAN_Name(std::string algo_spec); + + /** + * @return original input string + */ + std::string as_string() const { return orig_algo_spec; } + + /** + * @return algorithm name + */ + std::string algo_name() const { return alg_name; } + + /** + * @return algorithm name plus any arguments + */ + std::string algo_name_and_args() const; + + /** + * @return number of arguments + */ + size_t arg_count() const { return args.size(); } + + /** + * @param lower is the lower bound + * @param upper is the upper bound + * @return if the number of arguments is between lower and upper + */ + bool arg_count_between(size_t lower, size_t upper) const + { return ((arg_count() >= lower) && (arg_count() <= upper)); } + + /** + * @param i which argument + * @return ith argument + */ + std::string arg(size_t i) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument or the default value + */ + std::string arg(size_t i, const std::string& def_value) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument as an integer, or the default value + */ + size_t arg_as_integer(size_t i, size_t def_value) const; + + /** + * @return cipher mode (if any) + */ + std::string cipher_mode() const + { return (mode_info.size() >= 1) ? mode_info[0] : ""; } + + /** + * @return cipher mode padding (if any) + */ + std::string cipher_mode_pad() const + { return (mode_info.size() >= 2) ? mode_info[1] : ""; } + + private: + std::string orig_algo_spec; + std::string alg_name; + std::vector args; + std::vector mode_info; + }; + +} + + +namespace Botan { + +/** +* Represents the length requirements on an algorithm key +*/ +class BOTAN_DLL Key_Length_Specification + { + public: + /** + * Constructor for fixed length keys + * @param keylen the supported key length + */ + Key_Length_Specification(size_t keylen) : + min_keylen(keylen), + max_keylen(keylen), + keylen_mod(1) + { + } + + /** + * Constructor for variable length keys + * @param min_k the smallest supported key length + * @param max_k the largest supported key length + * @param k_mod the number of bytes the key must be a multiple of + */ + Key_Length_Specification(size_t min_k, + size_t max_k, + size_t k_mod = 1) : + min_keylen(min_k), + max_keylen(max_k ? max_k : min_k), + keylen_mod(k_mod) + { + } + + /** + * @param length is a key length in bytes + * @return true iff this length is a valid length for this algo + */ + bool valid_keylength(size_t length) const + { + return ((length >= min_keylen) && + (length <= max_keylen) && + (length % keylen_mod == 0)); + } + + /** + * @return minimum key length in bytes + */ + size_t minimum_keylength() const + { + return min_keylen; + } + + /** + * @return maximum key length in bytes + */ + size_t maximum_keylength() const + { + return max_keylen; + } + + /** + * @return key length multiple in bytes + */ + size_t keylength_multiple() const + { + return keylen_mod; + } + + private: + size_t min_keylen, max_keylen, keylen_mod; + }; + +} + + +namespace Botan { + +/** +* Octet String +*/ +class BOTAN_DLL OctetString + { + public: + /** + * @return size of this octet string in bytes + */ + size_t length() const { return bits.size(); } + + /** + * @return this object as a SecureVector + */ + SecureVector bits_of() const { return bits; } + + /** + * @return start of this string + */ + const byte* begin() const { return &bits[0]; } + + /** + * @return end of this string + */ + const byte* end() const { return &bits[bits.size()]; } + + /** + * @return this encoded as hex + */ + std::string as_string() const; + + /** + * XOR the contents of another octet string into this one + * @param other octet string + * @return reference to this + */ + OctetString& operator^=(const OctetString& other); + + /** + * Force to have odd parity + */ + void set_odd_parity(); + + /** + * Change the contents of this octet string + * @param hex_string a hex encoded bytestring + */ + void change(const std::string& hex_string); + + /** + * Change the contents of this octet string + * @param in the input + * @param length of in in bytes + */ + void change(const byte in[], size_t length); + + /** + * Change the contents of this octet string + * @param in the input + */ + void change(const MemoryRegion& in) { bits = in; } + + /** + * Create a new random OctetString + * @param rng is a random number generator + * @param len is the desired length in bytes + */ + OctetString(class RandomNumberGenerator& rng, size_t len); + + /** + * Create a new OctetString + * @param str is a hex encoded string + */ + OctetString(const std::string& str = "") { change(str); } + + /** + * Create a new OctetString + * @param in is an array + * @param len is the length of in in bytes + */ + OctetString(const byte in[], size_t len) { change(in, len); } + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const MemoryRegion& in) { change(in); } + private: + SecureVector bits; + }; + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is equal to y +*/ +BOTAN_DLL bool operator==(const OctetString& x, + const OctetString& y); + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is not equal to y +*/ +BOTAN_DLL bool operator!=(const OctetString& x, + const OctetString& y); + +/** +* Concatenate two strings +* @param x an octet string +* @param y an octet string +* @return x concatenated with y +*/ +BOTAN_DLL OctetString operator+(const OctetString& x, + const OctetString& y); + +/** +* XOR two strings +* @param x an octet string +* @param y an octet string +* @return x XORed with y +*/ +BOTAN_DLL OctetString operator^(const OctetString& x, + const OctetString& y); + + +/** +* Alternate name for octet string showing intent to use as a key +*/ +typedef OctetString SymmetricKey; + +/** +* Alternate name for octet string showing intent to use as an IV +*/ +typedef OctetString InitializationVector; + +} + + +namespace Botan { + +/** +* This class represents a symmetric algorithm object. +*/ +class BOTAN_DLL SymmetricAlgorithm : public Algorithm + { + public: + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * @return minimum allowed key length + */ + size_t maximum_keylength() const + { + return key_spec().maximum_keylength(); + } + + /** + * @return maxmium allowed key length + */ + size_t minimum_keylength() const + { + return key_spec().minimum_keylength(); + } + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this object. + * @param key the SymmetricKey to be set. + */ + void set_key(const SymmetricKey& key) + { set_key(key.begin(), key.length()); } + + /** + * Set the symmetric key of this object. + * @param key the to be set as a byte array. + * @param length in bytes of key param + */ + void set_key(const byte key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + private: + /** + * Run the key schedule + * @param key the key + * @param length of key + */ + virtual void key_schedule(const byte key[], size_t length) = 0; + }; + +/** +* The two possible directions for cipher filters, determining whether they +* actually perform encryption or decryption. +*/ +enum Cipher_Dir { ENCRYPTION, DECRYPTION }; + +} + + +namespace Botan { + +/** +* This class represents a block cipher object. +*/ +class BOTAN_DLL BlockCipher : public SymmetricAlgorithm + { + public: + + /** + * @return block size of this algorithm + */ + virtual size_t block_size() const = 0; + + /** + * @return native parallelism of this cipher in blocks + */ + virtual size_t parallelism() const { return 1; } + + /** + * @return prefererred parallelism of this cipher in bytes + */ + size_t parallel_bytes() const + { + return parallelism() * block_size() * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + + /** + * Encrypt a block. + * @param in The plaintext block to be encrypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the encrypted block. + * Must be of length block_size(). + */ + void encrypt(const byte in[], byte out[]) const + { encrypt_n(in, out, 1); } + + /** + * Decrypt a block. + * @param in The ciphertext block to be decypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the decrypted block. + * Must be of length block_size(). + */ + void decrypt(const byte in[], byte out[]) const + { decrypt_n(in, out, 1); } + + /** + * Encrypt a block. + * @param block the plaintext block to be encrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void encrypt(byte block[]) const { encrypt_n(block, block, 1); } + + /** + * Decrypt a block. + * @param block the ciphertext block to be decrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void decrypt(byte block[]) const { decrypt_n(block, block, 1); } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void encrypt_n(const byte in[], byte out[], + size_t blocks) const = 0; + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void decrypt_n(const byte in[], byte out[], + size_t blocks) const = 0; + + /** + * Get a new object representing the same algorithm as *this + */ + virtual BlockCipher* clone() const = 0; + }; + +/** +* Represents a block cipher with a single fixed block size +*/ +template +class Block_Cipher_Fixed_Params : public BlockCipher + { + public: + enum { BLOCK_SIZE = BS }; + size_t block_size() const { return BS; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(KMIN, KMAX, KMOD); + } + }; + +} + + +namespace Botan { + +/** +* Base class for all stream ciphers +*/ +class BOTAN_DLL StreamCipher : public SymmetricAlgorithm + { + public: + /** + * Encrypt or decrypt a message + * @param in the plaintext + * @param out the byte array to hold the output, i.e. the ciphertext + * @param len the length of both in and out in bytes + */ + virtual void cipher(const byte in[], byte out[], size_t len) = 0; + + /** + * Encrypt or decrypt a message + * @param buf the plaintext / ciphertext + * @param len the length of buf in bytes + */ + void cipher1(byte buf[], size_t len) + { cipher(buf, buf, len); } + + /** + * Resync the cipher using the IV + * @param iv the initialization vector + * @param iv_len the length of the IV in bytes + */ + virtual void set_iv(const byte iv[], size_t iv_len); + + /** + * @param iv_len the length of the IV in bytes + * @return if the length is valid for this algorithm + */ + virtual bool valid_iv_length(size_t iv_len) const; + + /** + * Get a new object representing the same algorithm as *this + */ + virtual StreamCipher* clone() const = 0; + }; + +} + + +namespace Botan { + +/** +* This class represents Message Authentication Code (MAC) objects. +*/ +class BOTAN_DLL MessageAuthenticationCode : public Buffered_Computation, + public SymmetricAlgorithm + { + public: + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @param length the length of param in + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const byte in[], size_t length); + + /** + * Get a new object representing the same algorithm as *this + */ + virtual MessageAuthenticationCode* clone() const = 0; + + /** + * Get the name of this algorithm. + * @return name of this algorithm + */ + virtual std::string name() const = 0; + }; + +} + + +namespace Botan { + +/** +* Base class for PBKDF (password based key derivation function) +* implementations. Converts a password into a key using a salt +* and iterated hashing to make brute force attacks harder. +*/ +class BOTAN_DLL PBKDF : public Algorithm + { + public: + + /** + * @return new instance of this same algorithm + */ + virtual PBKDF* clone() const = 0; + + void clear() {} + + /** + * Derive a key from a passphrase + * @param output_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + virtual OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const = 0; + }; + +/** +* For compatability with 1.8 +*/ +typedef PBKDF S2K; + +} + + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 8) + typedef byte word; +#elif (BOTAN_MP_WORD_BITS == 16) + typedef u16bit word; +#elif (BOTAN_MP_WORD_BITS == 32) + typedef u32bit word; +#elif (BOTAN_MP_WORD_BITS == 64) + typedef u64bit word; +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +const word MP_WORD_MASK = ~static_cast(0); +const word MP_WORD_TOP_BIT = static_cast(1) << (8*sizeof(word) - 1); +const word MP_WORD_MAX = MP_WORD_MASK; + +} + + +namespace Botan { + +/** +* Arbitrary precision integer +*/ +class BOTAN_DLL BigInt + { + public: + /** + * Base enumerator for encoding and decoding + */ + enum Base { Octal = 8, Decimal = 10, Hexadecimal = 16, Binary = 256 }; + + /** + * Sign symbol definitions for positive and negative numbers + */ + enum Sign { Negative = 0, Positive = 1 }; + + /** + * Number types (currently only power-of-2 supported) + */ + enum NumberType { Power2 }; + + /** + * DivideByZero Exception + */ + struct BOTAN_DLL DivideByZero : public Exception + { DivideByZero() : Exception("BigInt divide by zero") {} }; + + /** + * += operator + * @param y the BigInt to add to this + */ + BigInt& operator+=(const BigInt& y); + + /** + * -= operator + * @param y the BigInt to subtract from this + */ + BigInt& operator-=(const BigInt& y); + + /** + * *= operator + * @param y the BigInt to multiply with this + */ + BigInt& operator*=(const BigInt& y); + + /** + * /= operator + * @param y the BigInt to divide this by + */ + BigInt& operator/=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus to reduce this by + */ + BigInt& operator%=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus (word) to reduce this by + */ + word operator%=(word y); + + /** + * Left shift operator + * @param shift the number of bits to shift this left by + */ + BigInt& operator<<=(size_t shift); + + /** + * Right shift operator + * @param shift the number of bits to shift this right by + */ + BigInt& operator>>=(size_t shift); + + /** + * Increment operator + */ + BigInt& operator++() { return (*this += 1); } + + /** + * Decrement operator + */ + BigInt& operator--() { return (*this -= 1); } + + /** + * Postfix increment operator + */ + BigInt operator++(int) { BigInt x = (*this); ++(*this); return x; } + + /** + * Postfix decrement operator + */ + BigInt operator--(int) { BigInt x = (*this); --(*this); return x; } + + /** + * Unary negation operator + * @return negative this + */ + BigInt operator-() const; + + /** + * ! operator + * @return true iff this is zero, otherwise false + */ + bool operator !() const { return (!is_nonzero()); } + + /** + * [] operator (array access) + * @param i a word index + * @return the word at index i + */ + word& operator[](size_t i) { return reg[i]; } + + /** + * [] operator (array access) + * @param i a word index + * @return the word at index i + */ + const word& operator[](size_t i) const { return reg[i]; } + + /** + * Zeroize the BigInt + */ + void clear() { zeroise(reg); } + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @param check_signs include sign in comparison? + * @result if (thisn) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + s32bit cmp(const BigInt& n, bool check_signs = true) const; + + /** + * Test if the integer has an even value + * @result true if the integer is even, false otherwise + */ + bool is_even() const { return (get_bit(0) == 0); } + + /** + * Test if the integer has an odd value + * @result true if the integer is odd, false otherwise + */ + bool is_odd() const { return (get_bit(0) == 1); } + + /** + * Test if the integer is not zero + * @result true if the integer is non-zero, false otherwise + */ + bool is_nonzero() const { return (!is_zero()); } + + /** + * Test if the integer is zero + * @result true if the integer is zero, false otherwise + */ + bool is_zero() const + { + const size_t sw = sig_words(); + + for(size_t i = 0; i != sw; ++i) + if(reg[i]) + return false; + return true; + } + + /** + * Set bit at specified position + * @param n bit position to set + */ + void set_bit(size_t n); + + /** + * Clear bit at specified position + * @param n bit position to clear + */ + void clear_bit(size_t n); + + /** + * Clear all but the lowest n bits + * @param n amount of bits to keep + */ + void mask_bits(size_t n); + + /** + * Return bit value at specified position + * @param n the bit offset to test + * @result true, if the bit at position n is set, false otherwise + */ + bool get_bit(size_t n) const; + + /** + * Return (a maximum of) 32 bits of the complete value + * @param offset the offset to start extracting + * @param length amount of bits to extract (starting at offset) + * @result the integer extracted from the register starting at + * offset with specified length + */ + u32bit get_substring(size_t offset, size_t length) const; + + /** + * Convert this value into a u32bit, if it is in the range + * [0 ... 2**32-1], or otherwise throw an exception. + * @result the value as a u32bit if conversion is possible + */ + u32bit to_u32bit() const; + + /** + * @param n the offset to get a byte from + * @result byte at offset n + */ + byte byte_at(size_t n) const; + + /** + * Return the word at a specified position of the internal register + * @param n position in the register + * @return value at position n + */ + word word_at(size_t n) const + { return ((n < size()) ? reg[n] : 0); } + + /** + * Tests if the sign of the integer is negative + * @result true, iff the integer has a negative sign + */ + bool is_negative() const { return (sign() == Negative); } + + /** + * Tests if the sign of the integer is positive + * @result true, iff the integer has a positive sign + */ + bool is_positive() const { return (sign() == Positive); } + + /** + * Return the sign of the integer + * @result the sign of the integer + */ + Sign sign() const { return (signedness); } + + /** + * @result the opposite sign of the represented integer value + */ + Sign reverse_sign() const; + + /** + * Flip the sign of this BigInt + */ + void flip_sign(); + + /** + * Set sign of the integer + * @param sign new Sign to set + */ + void set_sign(Sign sign); + + /** + * @result absolute (positive) value of this + */ + BigInt abs() const; + + /** + * Give size of internal register + * @result size of internal register in words + */ + size_t size() const { return get_reg().size(); } + + /** + * Return how many words we need to hold this value + * @result significant words of the represented integer value + */ + size_t sig_words() const + { + const word* x = ®[0]; + size_t sig = reg.size(); + + while(sig && (x[sig-1] == 0)) + sig--; + return sig; + } + + /** + * Give byte length of the integer + * @result byte length of the represented integer value + */ + size_t bytes() const; + + /** + * Get the bit length of the integer + * @result bit length of the represented integer value + */ + size_t bits() const; + + /** + * Return a pointer to the big integer word register + * @result a pointer to the start of the internal register of + * the integer value + */ + const word* data() const { return ®[0]; } + + /** + * return a reference to the internal register containing the value + * @result a reference to the word-array (SecureVector) + * with the internal register value (containing the integer + * value) + */ + SecureVector& get_reg() { return reg; } + + /** + * return a const reference to the internal register containing the value + * @result a const reference to the word-array (SecureVector) + * with the internal register value (containing the integer value) + */ + const SecureVector& get_reg() const { return reg; } + + /** + * Assign using a plain word array + */ + void assign(const word x[], size_t length) + { + reg.resize(length); + copy_mem(®[0], x, length); + } + + /** + * Increase internal register buffer by n words + * @param n increase by n words + */ + void grow_reg(size_t n); + + void grow_to(size_t n); + + /** + * Fill BigInt with a random number with size of bitsize + * @param rng the random number generator to use + * @param bitsize number of bits the created random value should have + */ + void randomize(RandomNumberGenerator& rng, size_t bitsize = 0); + + /** + * Store BigInt-value in a given byte array + * @param buf destination byte array for the integer value + */ + void binary_encode(byte buf[]) const; + + /** + * Read integer value from a byte array with given size + * @param buf byte array buffer containing the integer + * @param length size of buf + */ + void binary_decode(const byte buf[], size_t length); + + /** + * Read integer value from a byte array (MemoryRegion) + * @param buf the array to load from + */ + void binary_decode(const MemoryRegion& buf); + + /** + * @param base the base to measure the size for + * @return size of this integer in base base + */ + size_t encoded_size(Base base = Binary) const; + + /** + * @param rng a random number generator + * @param min the minimum value + * @param max the maximum value + * @return random integer between min and max + */ + static BigInt random_integer(RandomNumberGenerator& rng, + const BigInt& min, + const BigInt& max); + + /** + * Encode the integer value from a BigInt to a SecureVector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result SecureVector of bytes containing the integer with given base + */ + static SecureVector encode(const BigInt& n, Base base = Binary); + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * value with given base + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + */ + static void encode(byte buf[], const BigInt& n, Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const byte buf[], size_t length, + Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const MemoryRegion& buf, + Base base = Binary); + + /** + * Encode a BigInt to a byte array according to IEEE 1363 + * @param n the BigInt to encode + * @param bytes the length of the resulting SecureVector + * @result a SecureVector containing the encoded BigInt + */ + static SecureVector encode_1363(const BigInt& n, size_t bytes); + + /** + * Swap this value with another + * @param other BigInt to swap values with + */ + void swap(BigInt& other); + + /** + * Create empty BigInt + */ + BigInt() { signedness = Positive; } + + /** + * Create BigInt from 64 bit integer + * @param n initial value of this BigInt + */ + BigInt(u64bit n); + + /** + * Copy Constructor + * @param other the BigInt to copy + */ + BigInt(const BigInt& other); + + /** + * Create BigInt from a string. If the string starts with 0x the + * rest of the string will be interpreted as hexadecimal digits. + * If the string starts with 0 and the second character is NOT an + * 'x' the string will be interpreted as octal digits. If the + * string starts with non-zero digit, it will be interpreted as a + * decimal number. + * + * @param str the string to parse for an integer value + */ + BigInt(const std::string& str); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param base is the number base of the integer in buf + */ + BigInt(const byte buf[], size_t length, Base base = Binary); + + /** + * Create a random BigInt of the specified size + * @param rng random number generator + * @param bits size in bits + */ + BigInt(RandomNumberGenerator& rng, size_t bits); + + /** + * Create BigInt of specified size, all zeros + * @param sign the sign + * @param n size of the internal register in words + */ + BigInt(Sign sign, size_t n); + + /** + * Create a number of the specified type and size + * @param type the type of number to create. For Power2, + * will create the integer 2^n + * @param n a size/length parameter, interpretation depends upon + * the value of type + */ + BigInt(NumberType type, size_t n); + + private: + SecureVector reg; + Sign signedness; + }; + +/* +* Arithmetic Operators +*/ +BigInt BOTAN_DLL operator+(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator-(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator*(const BigInt& x, const BigInt& y); +BigInt BOTAN_DLL operator/(const BigInt& x, const BigInt& d); +BigInt BOTAN_DLL operator%(const BigInt& x, const BigInt& m); +word BOTAN_DLL operator%(const BigInt& x, word m); +BigInt BOTAN_DLL operator<<(const BigInt& x, size_t n); +BigInt BOTAN_DLL operator>>(const BigInt& x, size_t n); + +/* +* Comparison Operators +*/ +inline bool operator==(const BigInt& a, const BigInt& b) + { return (a.cmp(b) == 0); } +inline bool operator!=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) != 0); } +inline bool operator<=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) <= 0); } +inline bool operator>=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) >= 0); } +inline bool operator<(const BigInt& a, const BigInt& b) + { return (a.cmp(b) < 0); } +inline bool operator>(const BigInt& a, const BigInt& b) + { return (a.cmp(b) > 0); } + +/* +* I/O Operators +*/ +BOTAN_DLL std::ostream& operator<<(std::ostream&, const BigInt&); +BOTAN_DLL std::istream& operator>>(std::istream&, BigInt&); + +} + +namespace std { + +template<> +inline void swap(Botan::BigInt& x, Botan::BigInt& y) + { + x.swap(y); + } + +} + + +namespace Botan { + +/** +* Modular Exponentiator Interface +*/ +class BOTAN_DLL Modular_Exponentiator + { + public: + virtual void set_base(const BigInt&) = 0; + virtual void set_exponent(const BigInt&) = 0; + virtual BigInt execute() const = 0; + virtual Modular_Exponentiator* copy() const = 0; + virtual ~Modular_Exponentiator() {} + }; + +/** +* Modular Exponentiator Proxy +*/ +class BOTAN_DLL Power_Mod + { + public: + + enum Usage_Hints { + NO_HINTS = 0x0000, + + BASE_IS_FIXED = 0x0001, + BASE_IS_SMALL = 0x0002, + BASE_IS_LARGE = 0x0004, + BASE_IS_2 = 0x0008, + + EXP_IS_FIXED = 0x0100, + EXP_IS_SMALL = 0x0200, + EXP_IS_LARGE = 0x0400 + }; + + /* + * Try to choose a good window size + */ + static size_t window_bits(size_t exp_bits, size_t base_bits, + Power_Mod::Usage_Hints hints); + + void set_modulus(const BigInt&, Usage_Hints = NO_HINTS) const; + void set_base(const BigInt&) const; + void set_exponent(const BigInt&) const; + + BigInt execute() const; + + Power_Mod& operator=(const Power_Mod&); + + Power_Mod(const BigInt& = 0, Usage_Hints = NO_HINTS); + Power_Mod(const Power_Mod&); + virtual ~Power_Mod(); + private: + mutable Modular_Exponentiator* core; + Usage_Hints hints; + }; + +/** +* Fixed Exponent Modular Exponentiator Proxy +*/ +class BOTAN_DLL Fixed_Exponent_Power_Mod : public Power_Mod + { + public: + BigInt operator()(const BigInt& b) const + { set_base(b); return execute(); } + + Fixed_Exponent_Power_Mod() {} + Fixed_Exponent_Power_Mod(const BigInt&, const BigInt&, + Usage_Hints = NO_HINTS); + }; + +/** +* Fixed Base Modular Exponentiator Proxy +*/ +class BOTAN_DLL Fixed_Base_Power_Mod : public Power_Mod + { + public: + BigInt operator()(const BigInt& e) const + { set_exponent(e); return execute(); } + + Fixed_Base_Power_Mod() {} + Fixed_Base_Power_Mod(const BigInt&, const BigInt&, + Usage_Hints = NO_HINTS); + }; + +} + + +namespace Botan { + +/** +* ASN.1 Type and Class Tags +*/ +enum ASN1_Tag { + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xC0, + + CONSTRUCTED = 0x20, + + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_TAG = 0x05, + OBJECT_ID = 0x06, + ENUMERATED = 0x0A, + SEQUENCE = 0x10, + SET = 0x11, + + UTF8_STRING = 0x0C, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + IA5_STRING = 0x16, + VISIBLE_STRING = 0x1A, + BMP_STRING = 0x1E, + + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + + NO_OBJECT = 0xFF00, + DIRECTORY_STRING = 0xFF01 +}; + +/** +* Basic ASN.1 Object Interface +*/ +class BOTAN_DLL ASN1_Object + { + public: + /** + * Encode whatever this object is into to + * @param to the DER_Encoder that will be written to + */ + virtual void encode_into(class DER_Encoder& to) const = 0; + + /** + * Decode whatever this object is from from + * @param from the BER_Decoder that will be read from + */ + virtual void decode_from(class BER_Decoder& from) = 0; + + virtual ~ASN1_Object() {} + }; + +/** +* BER Encoded Object +*/ +class BOTAN_DLL BER_Object + { + public: + void assert_is_a(ASN1_Tag, ASN1_Tag); + + ASN1_Tag type_tag, class_tag; + SecureVector value; + }; + +/* +* ASN.1 Utility Functions +*/ +class DataSource; + +namespace ASN1 { + +SecureVector put_in_sequence(const MemoryRegion& val); +std::string to_string(const BER_Object& obj); + +/** +* Heuristics tests; is this object possibly BER? +* @param src a data source that will be peeked at but not modified +*/ +bool maybe_BER(DataSource& src); + +} + +/** +* General BER Decoding Error Exception +*/ +struct BOTAN_DLL BER_Decoding_Error : public Decoding_Error + { + BER_Decoding_Error(const std::string&); + }; + +/** +* Exception For Incorrect BER Taggings +*/ +struct BOTAN_DLL BER_Bad_Tag : public BER_Decoding_Error + { + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag); + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2); + }; + +} + + +namespace Botan { + +/** +* This class represents ASN.1 object identifiers. +*/ +class BOTAN_DLL OID : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Find out whether this OID is empty + * @return true is no OID value is set + */ + bool is_empty() const { return id.size() == 0; } + + /** + * Get this OID as list (vector) of its components. + * @return vector representing this OID + */ + std::vector get_id() const { return id; } + + /** + * Get this OID as a string + * @return string representing this OID + */ + std::string as_string() const; + + /** + * Compare two OIDs. + * @return true if they are equal, false otherwise + */ + bool operator==(const OID&) const; + + /** + * Reset this instance to an empty OID. + */ + void clear(); + + /** + * Add a component to this OID. + * @param new_comp the new component to add to the end of this OID + * @return reference to *this + */ + OID& operator+=(u32bit new_comp); + + /** + * Construct an OID from a string. + * @param str a string in the form "a.b.c" etc., where a,b,c are numbers + */ + OID(const std::string& str = ""); + private: + std::vector id; + }; + +/** +* Append another component onto the OID. +* @param oid the OID to add the new component to +* @param new_comp the new component to add +*/ +OID operator+(const OID& oid, u32bit new_comp); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is not equal to b +*/ +bool operator!=(const OID& a, const OID& b); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is lexicographically smaller than b +*/ +bool operator<(const OID& a, const OID& b); + +} + + +namespace Botan { + +/** +* Algorithm Identifier +*/ +class BOTAN_DLL AlgorithmIdentifier : public ASN1_Object + { + public: + enum Encoding_Option { USE_NULL_PARAM }; + + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + AlgorithmIdentifier() {} + AlgorithmIdentifier(const OID&, Encoding_Option); + AlgorithmIdentifier(const std::string&, Encoding_Option); + + AlgorithmIdentifier(const OID&, const MemoryRegion&); + AlgorithmIdentifier(const std::string&, const MemoryRegion&); + + OID oid; + SecureVector parameters; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_DLL operator==(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); +bool BOTAN_DLL operator!=(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); + +} + + +namespace Botan { + +/** +* Public Key Base Class. +*/ +class BOTAN_DLL Public_Key + { + public: + /** + * Get the name of the underlying public key scheme. + * @return name of the public key scheme + */ + virtual std::string algo_name() const = 0; + + /** + * Get the OID of the underlying public key scheme. + * @return OID of the public key scheme + */ + virtual OID get_oid() const; + + /** + * Test the key values for consistency. + * @param rng rng to use + * @param strong whether to perform strong and lengthy version + * of the test + * @return true if the test is passed + */ + virtual bool check_key(RandomNumberGenerator& rng, + bool strong) const = 0; + + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts in bits + */ + virtual size_t message_part_size() const { return 0; } + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message size in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * @return X.509 AlgorithmIdentifier for this key + */ + virtual AlgorithmIdentifier algorithm_identifier() const = 0; + + /** + * @return X.509 subject key encoding for this key object + */ + virtual MemoryVector x509_subject_public_key() const = 0; + + virtual ~Public_Key() {} + protected: + /** + * Self-test after loading a key + * @param rng a random number generator + */ + virtual void load_check(RandomNumberGenerator& rng) const; + }; + +/** +* Private Key Base Class +*/ +class BOTAN_DLL Private_Key : public virtual Public_Key + { + public: + /** + * @return PKCS #8 private key encoding for this key object + */ + virtual MemoryVector pkcs8_private_key() const = 0; + + /** + * @return PKCS #8 AlgorithmIdentifier for this key + * Might be different from the X.509 identifier, but normally is not + */ + virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return algorithm_identifier(); } + + protected: + /** + * Self-test after loading a key + * @param rng a random number generator + */ + void load_check(RandomNumberGenerator& rng) const; + + /** + * Self-test after generating a key + * @param rng a random number generator + */ + void gen_check(RandomNumberGenerator& rng) const; + }; + +/** +* PK Secret Value Derivation Key +*/ +class BOTAN_DLL PK_Key_Agreement_Key : public virtual Private_Key + { + public: + /* + * @return public component of this key + */ + virtual MemoryVector public_value() const = 0; + + virtual ~PK_Key_Agreement_Key() {} + }; + +/* +* Typedefs +*/ +typedef PK_Key_Agreement_Key PK_KA_Key; +typedef Public_Key X509_PublicKey; +typedef Private_Key PKCS8_PrivateKey; + +} + + +namespace Botan { + +namespace PK_Ops { + +/** +* Public key encryption interface +*/ +class BOTAN_DLL Encryption + { + public: + virtual size_t max_input_bits() const = 0; + + virtual SecureVector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual ~Encryption() {} + }; + +/** +* Public key decryption interface +*/ +class BOTAN_DLL Decryption + { + public: + virtual size_t max_input_bits() const = 0; + + virtual SecureVector decrypt(const byte msg[], + size_t msg_len) = 0; + + virtual ~Decryption() {} + }; + +/** +* Public key signature creation interface +*/ +class BOTAN_DLL Signature + { + public: + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts + */ + virtual size_t message_part_size() const { return 0; } + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /* + * Perform a signature operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param rng a random number generator + */ + virtual SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual ~Signature() {} + }; + +/** +* Public key signature verification interface +*/ +class BOTAN_DLL Verification + { + public: + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * Find out the number of message parts supported by this scheme. + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return size of the message parts + */ + virtual size_t message_part_size() const { return 0; } + + /** + * @return boolean specifying if this key type supports message + * recovery and thus if you need to call verify() or verify_mr() + */ + virtual bool with_recovery() const = 0; + + /* + * Perform a signature check operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param sig the signature + * @param sig_len the length of sig in bytes + * @returns if signature is a valid one for message + */ + virtual bool verify(const byte[], size_t, + const byte[], size_t) + { + throw Invalid_State("Message recovery required"); + } + + /* + * Perform a signature operation (with message recovery) + * Only call this if with_recovery() returns true + * @param msg the message + * @param msg_len the length of msg in bytes + * @returns recovered message + */ + virtual SecureVector verify_mr(const byte[], + size_t) + { + throw Invalid_State("Message recovery not supported"); + } + + virtual ~Verification() {} + }; + +/** +* A generic key agreement Operation (eg DH or ECDH) +*/ +class BOTAN_DLL Key_Agreement + { + public: + /* + * Perform a key agreement operation + * @param w the other key value + * @param w_len the length of w in bytes + * @returns the agreed key + */ + virtual SecureVector agree(const byte w[], size_t w_len) = 0; + + virtual ~Key_Agreement() {} + }; + +} + +} + + +namespace Botan { + +class Algorithm_Factory; +class Keyed_Filter; + +/** +* Base class for all engines. All non-pure virtual functions simply +* return NULL, indicating the algorithm in question is not +* supported. Subclasses can reimplement whichever function(s) +* they want to hook in a particular type. +*/ +class BOTAN_DLL Engine + { + public: + virtual ~Engine() {} + + /** + * @return name of this engine + */ + virtual std::string provider_name() const = 0; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual BlockCipher* + find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual StreamCipher* + find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual HashFunction* + find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual MessageAuthenticationCode* + find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param n the modulus + * @param hints any use hints + * @return newly allocated object, or NULL + */ + virtual Modular_Exponentiator* + mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const; + + /** + * Return a new cipher object + * @param algo_spec the algorithm name/specification + * @param dir specifies if encryption or decryption is desired + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af); + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Signature* + get_signature_op(const Private_Key& key) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Verification* + get_verify_op(const Public_Key& key) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Encryption* + get_encryption_op(const Public_Key& key) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Decryption* + get_decryption_op(const Private_Key& key) const; + }; + +} + + +namespace Botan { + +/** +* Dynamically_Loaded_Engine just proxies the requests to the underlying +* Engine object, and handles load/unload details +*/ +class BOTAN_DLL Dynamically_Loaded_Engine : public Engine + { + public: + /** + * @param lib_path full pathname to DLL to load + */ + Dynamically_Loaded_Engine(const std::string& lib_path); + + ~Dynamically_Loaded_Engine(); + + std::string provider_name() const { return engine->provider_name(); } + + BlockCipher* find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { + return engine->find_block_cipher(algo_spec, af); + } + + StreamCipher* find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { + return engine->find_stream_cipher(algo_spec, af); + } + + HashFunction* find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { + return engine->find_hash(algo_spec, af); + } + + MessageAuthenticationCode* find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { + return engine->find_mac(algo_spec, af); + } + + PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { + return engine->find_pbkdf(algo_spec, af); + } + + Modular_Exponentiator* mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const + { + return engine->mod_exp(n, hints); + } + + Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af) + { + return engine->get_cipher(algo_spec, dir, af); + } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key) const + { + return engine->get_key_agreement_op(key); + } + + PK_Ops::Signature* + get_signature_op(const Private_Key& key) const + { + return engine->get_signature_op(key); + } + + PK_Ops::Verification* + get_verify_op(const Public_Key& key) const + { + return engine->get_verify_op(key); + } + + PK_Ops::Encryption* + get_encryption_op(const Public_Key& key) const + { + return engine->get_encryption_op(key); + } + + PK_Ops::Decryption* + get_decryption_op(const Private_Key& key) const + { + return engine->get_decryption_op(key); + } + + private: + class Dynamically_Loaded_Library* lib; + Engine* engine; + }; + +} + + +namespace Botan { + +/** +* Simple String +*/ +class BOTAN_DLL ASN1_String : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::string value() const; + std::string iso_8859() const; + + ASN1_Tag tagging() const; + + ASN1_String(const std::string& = ""); + ASN1_String(const std::string&, ASN1_Tag); + private: + std::string iso_8859_str; + ASN1_Tag tag; + }; + +} + + +namespace Botan { + +/** +* Attribute +*/ +class BOTAN_DLL Attribute : public ASN1_Object + { + public: + void encode_into(class DER_Encoder& to) const; + void decode_from(class BER_Decoder& from); + + OID oid; + MemoryVector parameters; + + Attribute() {} + Attribute(const OID&, const MemoryRegion&); + Attribute(const std::string&, const MemoryRegion&); + }; + +/** +* X.509 Time +*/ +class BOTAN_DLL X509_Time : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::string as_string() const; + std::string readable_string() const; + bool time_is_set() const; + + s32bit cmp(const X509_Time&) const; + + void set_to(const std::string&); + void set_to(const std::string&, ASN1_Tag); + + X509_Time(u64bit); + X509_Time(const std::string& = ""); + X509_Time(const std::string&, ASN1_Tag); + private: + bool passes_sanity_check() const; + u32bit year, month, day, hour, minute, second; + ASN1_Tag tag; + }; + +/** +* Alternative Name +*/ +class BOTAN_DLL AlternativeName : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::multimap contents() const; + + void add_attribute(const std::string&, const std::string&); + std::multimap get_attributes() const; + + void add_othername(const OID&, const std::string&, ASN1_Tag); + std::multimap get_othernames() const; + + bool has_items() const; + + AlternativeName(const std::string& = "", const std::string& = "", + const std::string& = "", const std::string& = ""); + private: + std::multimap alt_info; + std::multimap othernames; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_DLL operator==(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator!=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator<=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator>=(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator<(const X509_Time&, const X509_Time&); +bool BOTAN_DLL operator>(const X509_Time&, const X509_Time&); + +} + + +namespace Botan { + +/** +* This class represents an abstract data source object. +*/ +class BOTAN_DLL DataSource + { + public: + /** + * Read from the source. Moves the internal offset so that every + * call to read will return a new portion of the source. + * + * @param out the byte array to write the result to + * @param length the length of the byte array out + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t read(byte out[], size_t length) = 0; + + /** + * Read from the source but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the source starting at the same position. + * + * @param out the byte array to write the output to + * @param length the length of the byte array out + * @param peek_offset the offset into the stream to read at + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t peek(byte out[], size_t length, + size_t peek_offset) const = 0; + + /** + * Test whether the source still has data that can be read. + * @return true if there is still data to read, false otherwise + */ + virtual bool end_of_data() const = 0; + /** + * return the id of this data source + * @return std::string representing the id of this data source + */ + virtual std::string id() const { return ""; } + + /** + * Read one byte. + * @param out the byte to read to + * @return length in bytes that was actually read and put + * into out + */ + size_t read_byte(byte& out); + + /** + * Peek at one byte. + * @param out an output byte + * @return length in bytes that was actually read and put + * into out + */ + size_t peek_byte(byte& out) const; + + /** + * Discard the next N bytes of the data + * @param N the number of bytes to discard + * @return number of bytes actually discarded + */ + size_t discard_next(size_t N); + + DataSource() {} + virtual ~DataSource() {} + private: + DataSource& operator=(const DataSource&) { return (*this); } + DataSource(const DataSource&); + }; + +/** +* This class represents a Memory-Based DataSource +*/ +class BOTAN_DLL DataSource_Memory : public DataSource + { + public: + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t) const; + bool end_of_data() const; + + /** + * Construct a memory source that reads from a string + * @param in the string to read from + */ + DataSource_Memory(const std::string& in); + + /** + * Construct a memory source that reads from a byte array + * @param in the byte array to read from + * @param length the length of the byte array + */ + DataSource_Memory(const byte in[], size_t length); + + /** + * Construct a memory source that reads from a MemoryRegion + * @param in the MemoryRegion to read from + */ + DataSource_Memory(const MemoryRegion& in); + private: + SecureVector source; + size_t offset; + }; + +/** +* This class represents a Stream-Based DataSource. +*/ +class BOTAN_DLL DataSource_Stream : public DataSource + { + public: + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t) const; + bool end_of_data() const; + std::string id() const; + + DataSource_Stream(std::istream&, + const std::string& id = ""); + + /** + * Construct a Stream-Based DataSource from file + * @param file the name of the file + * @param use_binary whether to treat the file as binary or not + */ + DataSource_Stream(const std::string& file, bool use_binary = false); + + ~DataSource_Stream(); + private: + const std::string identifier; + + std::istream* source_p; + std::istream& source; + size_t total_read; + }; + +} + + +namespace Botan { + +/** +* This class represents general abstract filter objects. +*/ +class BOTAN_DLL Filter + { + public: + /** + * @return descriptive name for this filter + */ + virtual std::string name() const = 0; + + /** + * Write a portion of a message to this filter. + * @param input the input as a byte array + * @param length the length of the byte array input + */ + virtual void write(const byte input[], size_t length) = 0; + + /** + * Start a new message. Must be closed by end_msg() before another + * message can be started. + */ + virtual void start_msg() {} + + /** + * Notify that the current message is finished; flush buffers and + * do end-of-message processing (if any). + */ + virtual void end_msg() {} + + /** + * Check whether this filter is an attachable filter. + * @return true if this filter is attachable, false otherwise + */ + virtual bool attachable() { return true; } + + virtual ~Filter() {} + protected: + /** + * @param in some input for the filter + * @param length the length of in + */ + void send(const byte in[], size_t length); + + /** + * @param in some input for the filter + */ + void send(byte in) { send(&in, 1); } + + /** + * @param in some input for the filter + */ + void send(const MemoryRegion& in) { send(&in[0], in.size()); } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + void send(const MemoryRegion& in, size_t length) + { + send(&in[0], length); + } + + Filter(); + private: + Filter(const Filter&) {} + Filter& operator=(const Filter&) { return (*this); } + + /** + * Start a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void new_msg(); + + /** + * End a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void finish_msg(); + + friend class Pipe; + friend class Fanout_Filter; + + size_t total_ports() const; + size_t current_port() const { return port_num; } + + /** + * Set the active port + * @param new_port the new value + */ + void set_port(size_t new_port); + + size_t owns() const { return filter_owns; } + + /** + * Attach another filter to this one + * @param f filter to attach + */ + void attach(Filter* f); + + /** + * @param filters the filters to set + * @param count number of items in filters + */ + void set_next(Filter* filters[], size_t count); + Filter* get_next() const; + + SecureVector write_queue; + std::vector next; + size_t port_num, filter_owns; + + // true if filter belongs to a pipe --> prohibit filter sharing! + bool owned; + }; + +/** +* This is the abstract Fanout_Filter base class. +**/ +class BOTAN_DLL Fanout_Filter : public Filter + { + protected: + /** + * Increment the number of filters past us that we own + */ + void incr_owns() { ++filter_owns; } + + void set_port(size_t n) { Filter::set_port(n); } + + void set_next(Filter* f[], size_t n) { Filter::set_next(f, n); } + + void attach(Filter* f) { Filter::attach(f); } + }; + +/** +* The type of checking to be performed by decoders: +* NONE - no checks, IGNORE_WS - perform checks, but ignore +* whitespaces, FULL_CHECK - perform checks, also complain +* about white spaces. +*/ +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +} + + +namespace Botan { + +/** +* This class represents pipe objects. +* A set of filters can be 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. +*/ +class BOTAN_DLL Pipe : public DataSource + { + public: + /** + * An opaque type that identifies a message in this Pipe + */ + typedef size_t message_id; + + /** + * Exception if you use an invalid message as an argument to + * read, remaining, etc + */ + struct BOTAN_DLL Invalid_Message_Number : public Invalid_Argument + { + /** + * @param where the error occured + * @param msg the invalid message id that was used + */ + Invalid_Message_Number(const std::string& where, message_id msg) : + Invalid_Argument("Pipe::" + where + ": Invalid message number " + + to_string(msg)) + {} + }; + + /** + * A meta-id for whatever the last message is + */ + static const message_id LAST_MESSAGE; + + /** + * A meta-id for the default message (set with set_default_msg) + */ + static const message_id DEFAULT_MESSAGE; + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the byte array to write + * @param length the length of the byte array in + */ + void write(const byte in[], size_t length); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the MemoryRegion containing the data to write + */ + void write(const MemoryRegion& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the string containing the data to write + */ + void write(const std::string& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the DataSource to read the data from + */ + void write(DataSource& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in a single byte to be written + */ + void write(byte in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the byte array containing the data to write + * @param length the length of the byte array to write + */ + void process_msg(const byte in[], size_t length); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the MemoryRegion containing the data to write + */ + void process_msg(const MemoryRegion& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the string containing the data to write + */ + void process_msg(const std::string& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the DataSource providing the data to write + */ + void process_msg(DataSource& in); + + /** + * Find out how many bytes are ready to read. + * @param msg the number identifying the message + * for which the information is desired + * @return number of bytes that can still be read + */ + size_t remaining(message_id msg = DEFAULT_MESSAGE) const; + + /** + * Read the default message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @return number of bytes actually read into output + */ + size_t read(byte output[], size_t length); + + /** + * Read a specified message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @param msg the number identifying the message to read from + * @return number of bytes actually read into output + */ + size_t read(byte output[], size_t length, message_id msg); + + /** + * Read a single byte from the pipe. Moves the internal offset so + * that every call to read will return a new portion of the + * message. + * + * @param output the byte to write the result to + * @param msg the message to read from + * @return number of bytes actually read into output + */ + size_t read(byte& output, message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return SecureVector holding the contents of the pipe + */ + SecureVector read_all(message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return string holding the contents of the pipe + */ + std::string read_all_as_string(message_id = DEFAULT_MESSAGE); + + /** Read from the default message but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte output[], size_t length, size_t offset) const; + + /** Read from the specified message but do not modify the + * internal offset. Consecutive calls to peek() will return + * portions of the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte output[], size_t length, + size_t offset, message_id msg) const; + + /** Read a single byte from the specified message but do not + * modify the internal offset. Consecutive calls to peek() will + * return portions of the message starting at the same position. + * @param output the byte to write the peeked message byte to + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(byte& output, size_t offset, + message_id msg = DEFAULT_MESSAGE) const; + + /** + * @return currently set default message + */ + size_t default_msg() const { return default_read; } + + /** + * Set the default message + * @param msg the number identifying the message which is going to + * be the new default message + */ + void set_default_msg(message_id msg); + + /** + * Get the number of messages the are in this pipe. + * @return number of messages the are in this pipe + */ + message_id message_count() const; + + /** + * Test whether this pipe has any data that can be read from. + * @return true if there is more data to read, false otherwise + */ + bool end_of_data() const; + + /** + * Start a new message in the pipe. A potential other message in this pipe + * must be closed with end_msg() before this function may be called. + */ + void start_msg(); + + /** + * End the current message. + */ + void end_msg(); + + /** + * Insert a new filter at the front of the pipe + * @param filt the new filter to insert + */ + void prepend(Filter* filt); + + /** + * Insert a new filter at the back of the pipe + * @param filt the new filter to insert + */ + void append(Filter* filt); + + /** + * Remove the first filter at the front of the pipe. + */ + void pop(); + + /** + * Reset this pipe to an empty pipe. + */ + void reset(); + + /** + * Construct a Pipe of up to four filters. The filters are set up + * in the same order as the arguments. + */ + Pipe(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + + /** + * Construct a Pipe from range of filters passed as an array + * @param filters the set of filters to use + * @param count the number of elements in filters + */ + Pipe(Filter* filters[], size_t count); + ~Pipe(); + private: + Pipe(const Pipe&) : DataSource() {} + Pipe& operator=(const Pipe&) { return (*this); } + void init(); + void destruct(Filter*); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + + message_id get_message_no(const std::string&, message_id) const; + + Filter* pipe; + class Output_Buffers* outputs; + message_id default_read; + bool inside_msg; + }; + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out an output stream +* @param pipe the pipe +*/ +BOTAN_DLL std::ostream& operator<<(std::ostream& out, Pipe& pipe); + +/** +* Stream input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in the input stream +* @param pipe the pipe +*/ +BOTAN_DLL std::istream& operator>>(std::istream& in, Pipe& pipe); + +} + +#if defined(BOTAN_HAS_PIPE_UNIXFD_IO) + +namespace Botan { + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out file descriptor for an open output stream +* @param pipe the pipe +*/ +int BOTAN_DLL operator<<(int out, Pipe& pipe); + +/** +* File descriptor input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in file descriptor for an open input stream +* @param pipe the pipe +*/ +int BOTAN_DLL operator>>(int in, Pipe& pipe); + +} + +#endif + + +namespace Botan { + +/** +* BER Decoding Object +*/ +class BOTAN_DLL BER_Decoder + { + public: + BER_Object get_next_object(); + void push_back(const BER_Object&); + + bool more_items() const; + BER_Decoder& verify_end(); + BER_Decoder& discard_remaining(); + + BER_Decoder start_cons(ASN1_Tag, ASN1_Tag = UNIVERSAL); + BER_Decoder& end_cons(); + + BER_Decoder& raw_bytes(MemoryRegion&); + + BER_Decoder& decode_null(); + BER_Decoder& decode(bool&); + BER_Decoder& decode(size_t&); + BER_Decoder& decode(class BigInt&); + BER_Decoder& decode(MemoryRegion&, ASN1_Tag); + + BER_Decoder& decode(bool&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + BER_Decoder& decode(size_t&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + BER_Decoder& decode(class BigInt&, + ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + BER_Decoder& decode(MemoryRegion&, ASN1_Tag, + ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(class ASN1_Object&); + + BER_Decoder& decode_octet_string_bigint(class BigInt&); + + template + BER_Decoder& decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value = T()); + + template + BER_Decoder& decode_list(std::vector& out, + bool clear_out = true); + + template + BER_Decoder& decode_and_check(const T& expected, + const std::string& error_msg) + { + T actual; + decode(actual); + + if(actual != expected) + throw Decoding_Error(error_msg); + + return (*this); + } + + BER_Decoder& decode_optional_string(MemoryRegion&, + ASN1_Tag, u16bit); + + BER_Decoder(DataSource&); + BER_Decoder(const byte[], size_t); + BER_Decoder(const MemoryRegion&); + BER_Decoder(const BER_Decoder&); + ~BER_Decoder(); + private: + BER_Decoder& operator=(const BER_Decoder&) { return (*this); } + + BER_Decoder* parent; + DataSource* source; + BER_Object pushed; + mutable bool owns; + }; + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template +BER_Decoder& BER_Decoder::decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if(class_tag & CONSTRUCTED) + BER_Decoder(obj.value).decode(out).verify_end(); + else + { + push_back(obj); + decode(out, type_tag, class_tag); + } + } + else + { + out = default_value; + push_back(obj); + } + + return (*this); + } + +/* +* Decode a list of homogenously typed values +*/ +template +BER_Decoder& BER_Decoder::decode_list(std::vector& vec, bool clear_it) + { + if(clear_it) + vec.clear(); + + while(more_items()) + { + T value; + decode(value); + vec.push_back(value); + } + return (*this); + } + +} + + +namespace Botan { + +/** +* X.509v3 Key Constraints. +*/ +enum Key_Constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +/** +* BER Decoding Function for key constraints +*/ +namespace BER { + +void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&); + +} + +/** +* X.509v2 CRL Reason Code. +*/ +enum CRL_Code { + UNSPECIFIED = 0, + KEY_COMPROMISE = 1, + CA_COMPROMISE = 2, + AFFILIATION_CHANGED = 3, + SUPERSEDED = 4, + CESSATION_OF_OPERATION = 5, + CERTIFICATE_HOLD = 6, + REMOVE_FROM_CRL = 8, + PRIVLEDGE_WITHDRAWN = 9, + AA_COMPROMISE = 10, + + DELETE_CRL_ENTRY = 0xFF00, + OCSP_GOOD = 0xFF01, + OCSP_UNKNOWN = 0xFF02 +}; + +/* +* Various Other Enumerations +*/ + +/** +* The two types of X509 encoding supported by Botan. +*/ +enum X509_Encoding { RAW_BER, PEM }; + +} + + +namespace Botan { + +/** +* This class represents abstract X.509 signed objects as +* in the X.500 SIGNED macro +*/ +class BOTAN_DLL X509_Object + { + public: + /** + * The underlying data that is to be or was signed + * @return data that is or was signed + */ + MemoryVector tbs_data() const; + + /** + * @return signature on tbs_data() + */ + MemoryVector signature() const; + + /** + * @return signature algorithm that was used to generate signature + */ + AlgorithmIdentifier signature_algorithm() const; + + /** + * @return hash algorithm that was used to generate signature + */ + std::string hash_used_for_signature() const; + + /** + * Create a signed X509 object. + * @param signer the signer used to sign the object + * @param rng the random number generator to use + * @param alg_id the algorithm identifier of the signature scheme + * @param tbs the tbs bits to be signed + * @return signed X509 object + */ + static MemoryVector make_signed(class PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const MemoryRegion& tbs); + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return true if the signature is valid, otherwise false + */ + bool check_signature(class Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * the pointer will be deleted after use + * @return true if the signature is valid, otherwise false + */ + bool check_signature(class Public_Key* key) const; + + /** + * @return BER encoding of this + */ + MemoryVector BER_encode() const; + + /** + * @return PEM encoding of this + */ + std::string PEM_encode() const; + + /** + * Encode this to a pipe + * @deprecated use BER_encode or PEM_encode instead + * @param out the pipe to write to + * @param encoding the encoding to use + */ + BOTAN_DEPRECATED("Use BER_encode or PEM_encode") + void encode(Pipe& out, X509_Encoding encoding = PEM) const; + + virtual ~X509_Object() {} + protected: + X509_Object(DataSource& src, const std::string& pem_labels); + X509_Object(const std::string& file, const std::string& pem_labels); + + void do_decode(); + X509_Object() {} + AlgorithmIdentifier sig_algo; + MemoryVector tbs_bits, sig; + private: + virtual void force_decode() = 0; + void init(DataSource&, const std::string&); + void decode_info(DataSource&); + std::vector PEM_labels_allowed; + std::string PEM_label_pref; + }; + +} + + +namespace Botan { + +/** +* Distinguished Name +*/ +class BOTAN_DLL X509_DN : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + std::multimap get_attributes() const; + std::vector get_attribute(const std::string&) const; + + std::multimap contents() const; + + void add_attribute(const std::string&, const std::string&); + void add_attribute(const OID&, const std::string&); + + static std::string deref_info_field(const std::string&); + + MemoryVector get_bits() const; + + X509_DN(); + X509_DN(const std::multimap&); + X509_DN(const std::multimap&); + private: + std::multimap dn_info; + MemoryVector dn_bits; + }; + +bool BOTAN_DLL operator==(const X509_DN&, const X509_DN&); +bool BOTAN_DLL operator!=(const X509_DN&, const X509_DN&); +bool BOTAN_DLL operator<(const X509_DN&, const X509_DN&); + +} + + +namespace Botan { + +/** +* This namespace contains functions for handling X.509 public keys +*/ +namespace X509 { + +/** +* BER encode a key +* @param key the public key to encode +* @return BER encoding of this key +*/ +BOTAN_DLL MemoryVector BER_encode(const Public_Key& key); + +/** +* PEM encode a public key into a string. +* @param key the key to encode +* @return PEM encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Public_Key& key); + +/** +* Create a public key from a data source. +* @param source the source providing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(DataSource& source); + +/** +* Create a public key from a file +* @param filename pathname to the file to load +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(const std::string& filename); + +/** +* Create a public key from a memory region. +* @param enc the memory region containing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_DLL Public_Key* load_key(const MemoryRegion& enc); + +/** +* Copy a key. +* @param key the public key to copy +* @return new public key object +*/ +BOTAN_DLL Public_Key* copy_key(const Public_Key& key); + +/** +* Create the key constraints for a specific public key. +* @param pub_key the public key from which the basic set of +* constraints to be placed in the return value is derived +* @param limits additional limits that will be incorporated into the +* return value +* @return combination of key type specific constraints and +* additional limits +*/ +BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits); + +/** +* Encode a key into a pipe. +* @deprecated Use PEM_encode or BER_encode instead +* +* @param key the public key to encode +* @param pipe the pipe to feed the encoded key into +* @param encoding the encoding type to use +*/ +BOTAN_DEPRECATED("Use PEM_encode or BER_encode") +inline void encode(const Public_Key& key, + Pipe& pipe, + X509_Encoding encoding = PEM) + { + if(encoding == PEM) + pipe.write(X509::PEM_encode(key)); + else + pipe.write(X509::BER_encode(key)); + } + +} + +} + + +namespace Botan { + +/** +* Data Store +*/ +class BOTAN_DLL Data_Store + { + public: + /** + * A search function + */ + class BOTAN_DLL Matcher + { + public: + virtual bool operator()(const std::string&, + const std::string&) const = 0; + + virtual std::pair + transform(const std::string&, const std::string&) const; + + virtual ~Matcher() {} + }; + + bool operator==(const Data_Store&) const; + + std::multimap + search_with(const Matcher&) const; + + std::vector get(const std::string&) const; + + std::string get1(const std::string&) const; + + MemoryVector get1_memvec(const std::string&) const; + u32bit get1_u32bit(const std::string&, u32bit = 0) const; + + bool has_value(const std::string&) const; + + void add(const std::multimap&); + void add(const std::string&, const std::string&); + void add(const std::string&, u32bit); + void add(const std::string&, const MemoryRegion&); + private: + std::multimap contents; + }; + +} + + +namespace Botan { + +/** +* This class represents X.509 Certificate +*/ +class BOTAN_DLL X509_Certificate : public X509_Object + { + public: + /** + * Get the public key associated with this certificate. + * @return subject public key of this certificate + */ + Public_Key* subject_public_key() const; + + /** + * Get the issuer certificate DN. + * @return issuer DN of this certificate + */ + X509_DN issuer_dn() const; + + /** + * Get the subject certificate DN. + * @return subject DN of this certificate + */ + X509_DN subject_dn() const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the paramter to look up. Possible names are + * "X509.Certificate.version", "X509.Certificate.serial", + * "X509.Certificate.start", "X509.Certificate.end", + * "X509.Certificate.v2.key_id", "X509.Certificate.public_key", + * "X509v3.BasicConstraints.path_constraint", + * "X509v3.BasicConstraints.is_ca", "X509v3.ExtendedKeyUsage", + * "X509v3.CertificatePolicies", "X509v3.SubjectKeyIdentifier" or + * "X509.Certificate.serial". + * @return value(s) of the specified parameter + */ + std::vector subject_info(const std::string& name) const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the paramter to look up. Possible names are + * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier". + * @return value(s) of the specified parameter + */ + std::vector issuer_info(const std::string& name) const; + + /** + * Get the notBefore of the certificate. + * @return notBefore of the certificate + */ + std::string start_time() const; + + /** + * Get the notAfter of the certificate. + * @return notAfter of the certificate + */ + std::string end_time() const; + + /** + * Get the X509 version of this certificate object. + * @return X509 version + */ + u32bit x509_version() const; + + /** + * Get the serial number of this certificate. + * @return certificates serial number + */ + MemoryVector serial_number() const; + + /** + * Get the DER encoded AuthorityKeyIdentifier of this certificate. + * @return DER encoded AuthorityKeyIdentifier + */ + MemoryVector authority_key_id() const; + + /** + * Get the DER encoded SubjectKeyIdentifier of this certificate. + * @return DER encoded SubjectKeyIdentifier + */ + MemoryVector subject_key_id() const; + + /** + * Check whether this certificate is self signed. + * @return true if this certificate is self signed + */ + bool is_self_signed() const { return self_signed; } + + /** + * Check whether this certificate is a CA certificate. + * @return true if this certificate is a CA certificate + */ + bool is_CA_cert() const; + + /** + * Get the path limit as defined in the BasicConstraints extension of + * this certificate. + * @return path limit + */ + u32bit path_limit() const; + + /** + * Get the key constraints as defined in the KeyUsage extension of this + * certificate. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the key constraints as defined in the ExtendedKeyUsage + * extension of this + * certificate. + * @return key constraints + */ + std::vector ex_constraints() const; + + /** + * Get the policies as defined in the CertificatePolicies extension + * of this certificate. + * @return certificate policies + */ + std::vector policies() const; + + /** + * @return a string describing the certificate + */ + std::string to_string() const; + + /** + * Check to certificates for equality. + * @return true both certificates are (binary) equal + */ + bool operator==(const X509_Certificate& other) const; + + /** + * Create a certificate from a data source providing the DER or + * PEM encoded certificate. + * @param source the data source + */ + X509_Certificate(DataSource& source); + + /** + * Create a certificate from a file containing the DER or PEM + * encoded certificate. + * @param filename the name of the certificate file + */ + X509_Certificate(const std::string& filename); + private: + void force_decode(); + friend class X509_CA; + X509_Certificate() {} + + Data_Store subject, issuer; + bool self_signed; + }; + +/** +* Check two certificates for inequality +* @return true if the arguments represent different certificates, +* false if they are binary identical +*/ +BOTAN_DLL bool operator!=(const X509_Certificate&, const X509_Certificate&); + +/* +* Data Store Extraction Operations +*/ +BOTAN_DLL X509_DN create_dn(const Data_Store&); +BOTAN_DLL AlternativeName create_alt_name(const Data_Store&); + +} + + +namespace Botan { + +/** +* This class represents CRL entries +*/ +class BOTAN_DLL CRL_Entry : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + /** + * Get the serial number of the certificate associated with this entry. + * @return certificate's serial number + */ + MemoryVector serial_number() const { return serial; } + + /** + * Get the revocation date of the certificate associated with this entry + * @return certificate's revocation date + */ + X509_Time expire_time() const { return time; } + + /** + * Get the entries reason code + * @return reason code + */ + CRL_Code reason_code() const { return reason; } + + /** + * Construct an empty CRL entry. + */ + CRL_Entry(bool throw_on_unknown_critical_extension = false); + + /** + * Construct an CRL entry. + * @param cert the certificate to revoke + * @param reason the reason code to set in the entry + */ + CRL_Entry(const X509_Certificate& cert, + CRL_Code reason = UNSPECIFIED); + + private: + bool throw_on_unknown_critical; + MemoryVector serial; + X509_Time time; + CRL_Code reason; + }; + +/** +* Test two CRL entries for equality in all fields. +*/ +BOTAN_DLL bool operator==(const CRL_Entry&, const CRL_Entry&); + +/** +* Test two CRL entries for inequality in at least one field. +*/ +BOTAN_DLL bool operator!=(const CRL_Entry&, const CRL_Entry&); + +} + + +namespace Botan { + +/** +* This class represents X.509 Certificate Revocation Lists (CRLs). +*/ +class BOTAN_DLL X509_CRL : public X509_Object + { + public: + /** + * This class represents CRL related errors. + */ + struct BOTAN_DLL X509_CRL_Error : public Exception + { + X509_CRL_Error(const std::string& error) : + Exception("X509_CRL: " + error) {} + }; + + /** + * Get the entries of this CRL in the form of a vector. + * @return vector containing the entries of this CRL. + */ + std::vector get_revoked() const; + + /** + * Get the issuer DN of this CRL. + * @return CRLs issuer DN + */ + X509_DN issuer_dn() const; + + /** + * Get the AuthorityKeyIdentifier of this CRL. + * @return this CRLs AuthorityKeyIdentifier + */ + MemoryVector authority_key_id() const; + + /** + * Get the serial number of this CRL. + * @return CRLs serial number + */ + u32bit crl_number() const; + + /** + * Get the CRL's thisUpdate value. + * @return CRLs thisUpdate + */ + X509_Time this_update() const; + + /** + * Get the CRL's nextUpdate value. + * @return CRLs nextdUpdate + */ + X509_Time next_update() const; + + /** + * Construct a CRL from a data source. + * @param source the data source providing the DER or PEM encoded CRL. + * @param throw_on_unknown_critical should we throw an exception + * if an unknown CRL extension marked as critical is encountered. + */ + X509_CRL(DataSource& source, bool throw_on_unknown_critical = false); + + /** + * Construct a CRL from a file containing the DER or PEM encoded CRL. + * @param filename the name of the CRL file + * @param throw_on_unknown_critical should we throw an exception + * if an unknown CRL extension marked as critical is encountered. + */ + X509_CRL(const std::string& filename, + bool throw_on_unknown_critical = false); + private: + void force_decode(); + + bool throw_on_unknown_critical; + std::vector revoked; + Data_Store info; + }; + +} + + +namespace Botan { + +/** +* Luby-Rackoff block cipher construction +*/ +class BOTAN_DLL LubyRackoff : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return 2 * hash->output_length(); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(2, 32, 2); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * @param hash function to use to form the block cipher + */ + LubyRackoff(HashFunction* hash); + ~LubyRackoff() { delete hash; } + private: + void key_schedule(const byte[], size_t); + + HashFunction* hash; + SecureVector K1, K2; + }; + +} + + +namespace Botan { + +/** +* EMSA2 from IEEE 1363 +* Useful for Rabin-Williams +*/ +class BOTAN_DLL EMSA2 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA2(HashFunction* hash); + ~EMSA2() { delete hash; } + private: + void update(const byte[], size_t); + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + + SecureVector empty_hash; + HashFunction* hash; + byte hash_id; + }; + +} + + +namespace Botan { + +/** +* Fused multiply-add +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)+c +*/ +BigInt BOTAN_DLL mul_add(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused subtract-multiply +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a-b)*c +*/ +BigInt BOTAN_DLL sub_mul(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Return the absolute value +* @param n an integer +* @return absolute value of n +*/ +inline BigInt abs(const BigInt& n) { return n.abs(); } + +/** +* Compute the greatest common divisor +* @param x a positive integer +* @param y a positive integer +* @return gcd(x,y) +*/ +BigInt BOTAN_DLL gcd(const BigInt& x, const BigInt& y); + +/** +* Least common multiple +* @param x a positive integer +* @param y a positive integer +* @return z, smallest integer such that z % x == 0 and z % y == 0 +*/ +BigInt BOTAN_DLL lcm(const BigInt& x, const BigInt& y); + +/** +* @param x an integer +* @return (x*x) +*/ +BigInt BOTAN_DLL square(const BigInt& x); + +/** +* Modular inversion +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 +*/ +BigInt BOTAN_DLL inverse_mod(const BigInt& x, + const BigInt& modulus); + +/** +* Compute the Jacobi symbol. If n is prime, this is equivalent +* to the Legendre symbol. +* @see http://mathworld.wolfram.com/JacobiSymbol.html +* +* @param a is a non-negative integer +* @param n is an odd integer > 1 +* @return (n / m) +*/ +s32bit BOTAN_DLL jacobi(const BigInt& a, + const BigInt& n); + +/** +* Modular exponentation +* @param b an integer base +* @param x a positive exponent +* @param m a positive modulus +* @return (b^x) % m +*/ +BigInt BOTAN_DLL power_mod(const BigInt& b, + const BigInt& x, + const BigInt& m); + +/** +* Compute the square root of x modulo a prime using the +* Shanks-Tonnelli algorithm +* +* @param x the input +* @param p the prime +* @return y such that (y*y)%p == x, or -1 if no such integer +*/ +BigInt BOTAN_DLL ressol(const BigInt& x, const BigInt& p); + +/** +* @param x an integer +* @return count of the zero bits in x, or, equivalently, the largest +* value of n such that 2^n divides x evently +*/ +size_t BOTAN_DLL low_zero_bits(const BigInt& x); + +/** +* Primality Testing +* @param n a positive integer to test for primality +* @param rng a random number generator +* @param level how hard to test +* @return true if all primality tests passed, otherwise false +*/ +bool BOTAN_DLL primality_test(const BigInt& n, + RandomNumberGenerator& rng, + size_t level = 1); + +/** +* Quickly check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool quick_check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 0); } + +/** +* Check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 1); } + +/** +* Verify primality - this function is slow but useful if you want to +* ensure that a possibly malicious entity did not provide you with +* something that 'looks like' a prime +* @param n a positive integer to test for primality +* @param rng a random number generator +* @return true if all primality tests passed, otherwise false +*/ +inline bool verify_prime(const BigInt& n, RandomNumberGenerator& rng) + { return primality_test(n, rng, 2); } + +/** +* Randomly generate a prime +* @param rng a random number generator +* @param bits how large the resulting prime should be in bits +* @param coprime a positive integer the result should be coprime to +* @param equiv a non-negative number that the result should be + equivalent to modulo equiv_mod +* @param equiv_mod the modulus equiv should be checked against +* @return random prime with the specified criteria +*/ +BigInt BOTAN_DLL random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime = 1, + size_t equiv = 1, size_t equiv_mod = 2); + +/** +* Return a 'safe' prime, of the form p=2*q+1 with q prime +* @param rng a random number generator +* @param bits is how long the resulting prime should be +* @return prime randomly chosen from safe primes of length bits +*/ +BigInt BOTAN_DLL random_safe_prime(RandomNumberGenerator& rng, + size_t bits); + +class Algorithm_Factory; + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param af an algorithm factory +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @return random seed used to generate this parameter set +*/ +SecureVector BOTAN_DLL +generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param af an algorithm factory +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @param seed the seed used to generate the parameters +* @return true if seed generated a valid DSA parameter set, otherwise + false. p_out and q_out are only valid if true was returned. +*/ +bool BOTAN_DLL +generate_dsa_primes(RandomNumberGenerator& rng, + Algorithm_Factory& af, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits, + const MemoryRegion& seed); + +/** +* The size of the PRIMES[] array +*/ +const size_t PRIME_TABLE_SIZE = 6541; + +/** +* A const array of all primes less than 65535 +*/ +extern const u16bit BOTAN_DLL PRIMES[]; + +} + + +namespace Botan { + +/** +* This class represents an elliptic curve over GF(p) +*/ +class BOTAN_DLL CurveGFp + { + public: + + /** + * Create an uninitialized CurveGFp + */ + CurveGFp() {} + + /** + * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) + * @param p prime number of the field + * @param a first coefficient + * @param b second coefficient + */ + CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : + p(p), a(a), b(b), p_words(p.sig_words()) + { + BigInt r(BigInt::Power2, p_words * BOTAN_MP_WORD_BITS); + + p_dash = (((r * inverse_mod(r, p)) - 1) / p).word_at(0); + + r2 = (r * r) % p; + a_r = (a * r) % p; + b_r = (b * r) % p; + } + + // CurveGFp(const CurveGFp& other) = default; + // CurveGFp& operator=(const CurveGFp& other) = default; + + /** + * @return curve coefficient a + */ + const BigInt& get_a() const { return a; } + + /** + * @return curve coefficient b + */ + const BigInt& get_b() const { return b; } + + /** + * Get prime modulus of the field of the curve + * @return prime modulus of the field of the curve + */ + const BigInt& get_p() const { return p; } + + /** + * @return Montgomery parameter r^2 % p + */ + const BigInt& get_r2() const { return r2; } + + /** + * @return a * r mod p + */ + const BigInt& get_a_r() const { return a_r; } + + /** + * @return b * r mod p + */ + const BigInt& get_b_r() const { return b_r; } + + /** + * @return Montgomery parameter p-dash + */ + word get_p_dash() const { return p_dash; } + + /** + * @return p.sig_words() + */ + size_t get_p_words() const { return p_words; } + + /** + * swaps the states of *this and other, does not throw + * @param other curve to swap values with + */ + void swap(CurveGFp& other) + { + std::swap(p, other.p); + + std::swap(a, other.a); + std::swap(b, other.b); + + std::swap(a_r, other.a_r); + std::swap(b_r, other.b_r); + + std::swap(p_words, other.p_words); + + std::swap(r2, other.r2); + std::swap(p_dash, other.p_dash); + } + + /** + * Equality operator + * @param other curve to compare with + * @return true iff this is the same curve as other + */ + bool operator==(const CurveGFp& other) const + { + /* + Relies on choice of R, but that is fixed by constructor based + on size of p + */ + return (p == other.p && a_r == other.a_r && b_r == other.b_r); + } + + private: + // Curve parameters + BigInt p, a, b; + + size_t p_words; // cache of p.sig_words() + + // Montgomery parameters + BigInt r2, a_r, b_r; + word p_dash; + }; + +/** +* Equality operator +* @param lhs a curve +* @param rhs a curve +* @return true iff lhs is not the same as rhs +*/ +inline bool operator!=(const CurveGFp& lhs, const CurveGFp& rhs) + { + return !(lhs == rhs); + } + +} + +namespace std { + +template<> inline +void swap(Botan::CurveGFp& curve1, + Botan::CurveGFp& curve2) + { + curve1.swap(curve2); + } + +} // namespace std + + +namespace Botan { + +/** +* Exception thrown if you try to convert a zero point to an affine +* coordinate +*/ +struct BOTAN_DLL Illegal_Transformation : public Exception + { + Illegal_Transformation(const std::string& err = + "Requested transformation is not possible") : + Exception(err) {} + }; + +/** +* Exception thrown if some form of illegal point is decoded +*/ +struct BOTAN_DLL Illegal_Point : public Exception + { + Illegal_Point(const std::string& err = "Malformed ECP point detected") : + Exception(err) {} + }; + +/** +* This class represents one point on a curve of GF(p) +*/ +class BOTAN_DLL PointGFp + { + public: + enum Compression_Type { + UNCOMPRESSED = 0, + COMPRESSED = 1, + HYBRID = 2 + }; + + /** + * Construct an uninitialized PointGFp + */ + PointGFp() {} + + /** + * Construct the zero point + * @param curve The base curve + */ + PointGFp(const CurveGFp& curve); + + /** + * Construct a point from its affine coordinates + * @param curve the base curve + * @param x affine x coordinate + * @param y affine y coordinate + */ + PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y); + + //PointGFp(const PointGFp& other) = default; + //PointGFp& operator=(const PointGFp& other) = default; + + /** + * += Operator + * @param rhs the PointGFp to add to the local value + * @result resulting PointGFp + */ + PointGFp& operator+=(const PointGFp& rhs); + + /** + * -= Operator + * @param rhs the PointGFp to subtract from the local value + * @result resulting PointGFp + */ + PointGFp& operator-=(const PointGFp& rhs); + + /** + * *= Operator + * @param scalar the PointGFp to multiply with *this + * @result resulting PointGFp + */ + PointGFp& operator*=(const BigInt& scalar); + + /** + * Multiplication Operator + * @param scalar the scalar value + * @param point the point value + * @return scalar*point on the curve + */ + friend BOTAN_DLL PointGFp operator*(const BigInt& scalar, const PointGFp& point); + + /** + * Multiexponentiation + * @param p1 a point + * @param z1 a scalar + * @param p2 a point + * @param z2 a scalar + * @result (p1 * z1 + p2 * z2) + */ + friend BOTAN_DLL PointGFp multi_exponentiate( + const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2); + + /** + * Negate this point + * @return *this + */ + PointGFp& negate() + { + if(!is_zero()) + coord_y = curve.get_p() - coord_y; + return *this; + } + + /** + * Return base curve of this point + * @result the curve over GF(p) of this point + */ + const CurveGFp& get_curve() const { return curve; } + + /** + * get affine x coordinate + * @result affine x coordinate + */ + BigInt get_affine_x() const; + + /** + * get affine y coordinate + * @result affine y coordinate + */ + BigInt get_affine_y() const; + + /** + * Is this the point at infinity? + * @result true, if this point is at infinity, false otherwise. + */ + bool is_zero() const + { return (coord_x.is_zero() && coord_z.is_zero()); } + + /** + * Checks whether the point is to be found on the underlying + * curve; used to prevent fault attacks. + * @return if the point is on the curve + */ + bool on_the_curve() const; + + /** + * swaps the states of *this and other, does not throw! + * @param other the object to swap values with + */ + void swap(PointGFp& other); + + /** + * Equality operator + */ + bool operator==(const PointGFp& other) const; + private: + + /** + * Montgomery multiplication/reduction + * @param x first multiplicand + * @param y second multiplicand + * @param workspace temp space + */ + BigInt monty_mult(const BigInt& x, const BigInt& y) const + { + BigInt result; + monty_mult(result, x, y); + return result; + } + + /** + * Montgomery multiplication/reduction + * @warning z cannot alias x or y + * @param z output + * @param x first multiplicand + * @param y second multiplicand + */ + void monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const; + + /** + * Montgomery squaring/reduction + * @param x multiplicand + */ + BigInt monty_sqr(const BigInt& x) const + { + BigInt result; + monty_sqr(result, x); + return result; + } + + /** + * Montgomery squaring/reduction + * @warning z cannot alias x + * @param z output + * @param x multiplicand + */ + void monty_sqr(BigInt& z, const BigInt& x) const; + + /** + * Point addition + * @param workspace temp space, at least 11 elements + */ + void add(const PointGFp& other, std::vector& workspace); + + /** + * Point doubling + * @param workspace temp space, at least 9 elements + */ + void mult2(std::vector& workspace); + + CurveGFp curve; + BigInt coord_x, coord_y, coord_z; + mutable SecureVector ws; // workspace for Montgomery + }; + +// relational operators +inline bool operator!=(const PointGFp& lhs, const PointGFp& rhs) + { + return !(rhs == lhs); + } + +// arithmetic operators +inline PointGFp operator-(const PointGFp& lhs) + { + return PointGFp(lhs).negate(); + } + +inline PointGFp operator+(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp += rhs; + } + +inline PointGFp operator-(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp -= rhs; + } + +inline PointGFp operator*(const PointGFp& point, const BigInt& scalar) + { + return scalar * point; + } + +// encoding and decoding +SecureVector BOTAN_DLL EC2OSP(const PointGFp& point, byte format); + +PointGFp BOTAN_DLL OS2ECP(const byte data[], size_t data_len, + const CurveGFp& curve); + +inline PointGFp OS2ECP(const MemoryRegion& data, const CurveGFp& curve) + { return OS2ECP(&data[0], data.size(), curve); } + +} + +namespace std { + +template<> +inline void swap(Botan::PointGFp& x, Botan::PointGFp& y) + { x.swap(y); } + +} + + +namespace Botan { + +/** +* This class represents elliptic curce domain parameters +*/ +enum EC_Group_Encoding { + EC_DOMPAR_ENC_EXPLICIT = 0, + EC_DOMPAR_ENC_IMPLICITCA = 1, + EC_DOMPAR_ENC_OID = 2 +}; + +/** +* Class representing an elliptic curve +*/ +class BOTAN_DLL EC_Group + { + public: + + /** + * Construct Domain paramers from specified parameters + * @param curve elliptic curve + * @param base_point a base point + * @param order the order of the base point + * @param cofactor the cofactor + */ + EC_Group(const CurveGFp& curve, + const PointGFp& base_point, + const BigInt& order, + const BigInt& cofactor) : + curve(curve), + base_point(base_point), + order(order), + cofactor(cofactor), + oid("") + {} + + /** + * Decode a BER encoded ECC domain parameter set + * @param ber_encoding the bytes of the BER encoding + */ + EC_Group(const MemoryRegion& ber_encoding); + + /** + * Create an EC domain by OID (or throw if unknown) + * @param oid the OID of the EC domain to create + */ + EC_Group(const OID& oid); + + /** + * Create an EC domain from PEM encoding (as from PEM_encode), + * or from an OID name (eg "secp160r1", or "1.3.132.0.8") + * @param pem_or_oid PEM-encoded data, or an OID + */ + EC_Group(const std::string& pem_or_oid = ""); + + /** + * Create the DER encoding of this domain + * @param form of encoding to use + * @returns bytes encododed as DER + */ + SecureVector DER_encode(EC_Group_Encoding form) const; + + /** + * Return the PEM encoding (always in explicit form) + * @return string containing PEM data + */ + std::string PEM_encode() const; + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const CurveGFp& get_curve() const { return curve; } + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const PointGFp& get_base_point() const { return base_point; } + + /** + * Return the order of the base point + * @result order of the base point + */ + const BigInt& get_order() const { return order; } + + /** + * Return the cofactor + * @result the cofactor + */ + const BigInt& get_cofactor() const { return cofactor; } + + bool initialized() const { return !base_point.is_zero(); } + + /** + * Return the OID of these domain parameters + * @result the OID + */ + std::string get_oid() const { return oid; } + + bool operator==(const EC_Group& other) const + { + return ((get_curve() == other.get_curve()) && + (get_base_point() == other.get_base_point()) && + (get_order() == other.get_order()) && + (get_cofactor() == other.get_cofactor())); + } + + private: + CurveGFp curve; + PointGFp base_point; + BigInt order, cofactor; + std::string oid; + }; + +inline bool operator!=(const EC_Group& lhs, + const EC_Group& rhs) + { + return !(lhs == rhs); + } + +// For compatability with 1.8 +typedef EC_Group EC_Domain_Params; + +} + + +namespace Botan { + +/** +* User Interface +* Only really used for callbacks for PKCS #8 decryption +*/ +class BOTAN_DLL User_Interface + { + public: + enum UI_Result { OK, CANCEL_ACTION }; + + virtual std::string get_passphrase(const std::string&, + const std::string&, + UI_Result&) const; + User_Interface(const std::string& = ""); + virtual ~User_Interface() {} + protected: + std::string preset_passphrase; + mutable bool first_try; + }; + +} + + +namespace Botan { + +/** +* PKCS #8 General Exception +*/ +struct BOTAN_DLL PKCS8_Exception : public Decoding_Error + { + PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +/** +* This namespace contains functions for handling PKCS #8 private keys +*/ +namespace PKCS8 { + +/** +* BER encode a private key +* @param key the private key to encode +* @return BER encoded key +*/ +BOTAN_DLL SecureVector BER_encode(const Private_Key& key); + +/** +* Get a string containing a PEM encoded private key. +* @param key the key to encode +* @return encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Private_Key& key); + +/** +* Encrypt a key using PKCS #8 encryption +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbe_algo the name of the desired password-based encryption + algorithm; if empty ("") a reasonable (portable/secure) + default will be chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_DLL SecureVector BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbe_algo the name of the desired password-based encryption + algorithm; if empty ("") a reasonable (portable/secure) + default will be chosen. +* @return encrypted key in PEM form +*/ +BOTAN_DLL std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo = ""); + + +/** +* Encode a private key into a pipe. +* @deprecated Use PEM_encode or BER_encode instead +* +* @param key the private key to encode +* @param pipe the pipe to feed the encoded key into +* @param encoding the encoding type to use +*/ +BOTAN_DEPRECATED("Use PEM_encode or BER_encode") +inline void encode(const Private_Key& key, + Pipe& pipe, + X509_Encoding encoding = PEM) + { + if(encoding == PEM) + pipe.write(PKCS8::PEM_encode(key)); + else + pipe.write(PKCS8::BER_encode(key)); + } + +/** +* Encode and encrypt a private key into a pipe. +* @deprecated Use PEM_encode or BER_encode instead +* +* @param key the private key to encode +* @param pipe the pipe to feed the encoded key into +* @param pass the password to use for encryption +* @param rng the rng to use +* @param pbe_algo the name of the desired password-based encryption + algorithm; if empty ("") a reasonable (portable/secure) + default will be chosen. +* @param encoding the encoding type to use +*/ +BOTAN_DEPRECATED("Use PEM_encode or BER_encode") +inline void encrypt_key(const Private_Key& key, + Pipe& pipe, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo = "", + X509_Encoding encoding = PEM) + { + if(encoding == PEM) + pipe.write(PKCS8::PEM_encode(key, rng, pass, pbe_algo)); + else + pipe.write(PKCS8::BER_encode(key, rng, pass, pbe_algo)); + } + +/** +* Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param ui the user interface to be used for passphrase dialog +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const User_Interface& ui); + +/** Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encoded. +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param ui the user interface to be used for passphrase dialog +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const User_Interface& ui); + +/** Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encoded. +* @return loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @param rng the rng to use +* @return new copy of the key +*/ +BOTAN_DLL Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng); + +} + +} + + +namespace Botan { + +/** +* This class represents abstract ECC public keys. When encoding a key +* via an encoder that can be accessed via the corresponding member +* functions, the key will decide upon its internally stored encoding +* information whether to encode itself with or without domain +* parameters, or using the domain parameter oid. Furthermore, a public +* key without domain parameters can be decoded. In that case, it +* cannot be used for verification until its domain parameters are set +* by calling the corresponding member function. +*/ +class BOTAN_DLL EC_PublicKey : public virtual Public_Key + { + public: + EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point); + + EC_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + /** + * Get the public point of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the public point of this key + */ + const PointGFp& public_point() const { return public_key; } + + AlgorithmIdentifier algorithm_identifier() const; + + MemoryVector x509_subject_public_key() const; + + bool check_key(RandomNumberGenerator& rng, + bool strong) const; + + /** + * Get the domain parameters of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the domain parameters of this key + */ + const EC_Group& domain() const { return domain_params; } + + /** + * Set the domain parameter encoding to be used when encoding this key. + * @param enc the encoding to use + */ + void set_parameter_encoding(EC_Group_Encoding enc); + + /** + * Return the DER encoding of this keys domain in whatever format + * is preset for this particular key + */ + MemoryVector DER_domain() const + { return domain().DER_encode(domain_format()); } + + /** + * Get the domain parameter encoding to be used when encoding this key. + * @result the encoding to use + */ + EC_Group_Encoding domain_format() const + { return domain_encoding; } + protected: + EC_PublicKey() : domain_encoding(EC_DOMPAR_ENC_EXPLICIT) {} + + EC_Group domain_params; + PointGFp public_key; + EC_Group_Encoding domain_encoding; + }; + +/** +* This abstract class represents ECC private keys +*/ +class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, + public virtual Private_Key + { + public: + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& private_key); + + EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + MemoryVector pkcs8_private_key() const; + + /** + * Get the private key value of this key object. + * @result the private key value of this key object + */ + const BigInt& private_value() const; + protected: + EC_PrivateKey() {} + + BigInt private_key; + }; + +} + + +namespace Botan { + +/** +* GOST-34.10 Public Key +*/ +class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + GOST_3410_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Construct from X.509 algorithm id and subject public key bits + */ + GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + /** + * Get this keys algorithm name. + * @result this keys algorithm name + */ + std::string algo_name() const { return "GOST-34.10"; } + + AlgorithmIdentifier algorithm_identifier() const; + + MemoryVector x509_subject_public_key() const; + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @result the maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + size_t message_parts() const { return 2; } + + size_t message_part_size() const + { return domain().get_order().bytes(); } + + protected: + GOST_3410_PublicKey() {} + }; + +/** +* GOST-34.10 Private Key +*/ +class BOTAN_DLL GOST_3410_PrivateKey : public GOST_3410_PublicKey, + public EC_PrivateKey + { + public: + + GOST_3410_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + GOST_3410_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return EC_PublicKey::algorithm_identifier(); } + }; + +/** +* GOST-34.10 signature operation +*/ +class BOTAN_DLL GOST_3410_Signature_Operation : public PK_Ops::Signature + { + public: + GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + private: + const PointGFp& base_point; + const BigInt& order; + const BigInt& x; + }; + +/** +* GOST-34.10 verification operation +*/ +class BOTAN_DLL GOST_3410_Verification_Operation : public PK_Ops::Verification + { + public: + GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const PointGFp& base_point; + const PointGFp& public_point; + const BigInt& order; + }; + +} + + +namespace Botan { + +/** +* MDx Hash Function Base Class +*/ +class BOTAN_DLL MDx_HashFunction : public HashFunction + { + public: + /** + * @param block_length is the number of bytes per block + * @param big_byte_endian specifies if the hash uses big-endian bytes + * @param big_bit_endian specifies if the hash uses big-endian bits + * @param counter_size specifies the size of the counter var in bytes + */ + MDx_HashFunction(size_t block_length, + bool big_byte_endian, + bool big_bit_endian, + size_t counter_size = 8); + + size_t hash_block_size() const { return buffer.size(); } + protected: + void add_data(const byte input[], size_t length); + void final_result(byte output[]); + + /** + * Run the hash's compression function over a set of blocks + * @param blocks the input + * @param block_n the number of blocks + */ + virtual void compress_n(const byte blocks[], size_t block_n) = 0; + + void clear(); + + /** + * Copy the output to the buffer + * @param buffer to put the output into + */ + virtual void copy_out(byte buffer[]) = 0; + + /** + * Write the count, if used, to this spot + * @param out where to write the counter to + */ + virtual void write_count(byte out[]); + private: + SecureVector buffer; + u64bit count; + size_t position; + + const bool BIG_BYTE_ENDIAN, BIG_BIT_ENDIAN; + const size_t COUNT_SIZE; + }; + +} + + +namespace Botan { + +/** +* HAS-160, a Korean hash function standardized in +* TTAS.KO-12.0011/R1. Used in conjuction with KCDSA +*/ +class BOTAN_DLL HAS_160 : public MDx_HashFunction + { + public: + std::string name() const { return "HAS-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new HAS_160; } + + void clear(); + + HAS_160() : MDx_HashFunction(64, false, true), X(20), digest(5) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector X, digest; + }; + +} + + +namespace Botan { + +/** +* This class represents the Library Initialization/Shutdown Object. It +* has to exceed the lifetime of any Botan object used in an +* application. You can call initialize/deinitialize or use +* LibraryInitializer in the RAII style. +*/ +class BOTAN_DLL LibraryInitializer + { + public: + /** + * Initialize the library + * @param options a string listing initialization options + */ + static void initialize(const std::string& options = ""); + + /** + * Shutdown the library + */ + static void deinitialize(); + + /** + * Initialize the library + * @param options a string listing initialization options + */ + LibraryInitializer(const std::string& options = "") + { LibraryInitializer::initialize(options); } + + ~LibraryInitializer() { LibraryInitializer::deinitialize(); } + }; + +} + + +namespace Botan { + +/* +* Forward declare to avoid recursive dependency between this header +* and libstate.h +*/ +class Library_State; + +/** +* Namespace for management of the global state +*/ +namespace Global_State_Management { + +/** +* Access the global library state +* @return reference to the global library state +*/ +BOTAN_DLL Library_State& global_state(); + +/** +* Set the global state object +* @param state the new global state to use +*/ +BOTAN_DLL void set_global_state(Library_State* state); + +/** +* Set the global state object unless it is already set +* @param state the new global state to use +* @return true if the state parameter is now being used as the global +* state, or false if one was already set, in which case the +* parameter was deleted immediately +*/ +BOTAN_DLL bool set_global_state_unless_set(Library_State* state); + +/** +* Swap the current state for another +* @param new_state the new state object to use +* @return previous state (or NULL if none) +*/ +BOTAN_DLL Library_State* swap_global_state(Library_State* new_state); + +/** +* Query if the library is currently initialized +* @return true iff the library is initialized +*/ +BOTAN_DLL bool global_state_exists(); + +} + +/* +* Insert into Botan ns for convenience/backwards compatability +*/ +using Global_State_Management::global_state; + +} + + +namespace Botan { + +/** +* Forward declarations (don't need full definitions here) +*/ +class BlockCipher; +class StreamCipher; +class HashFunction; +class MessageAuthenticationCode; +class PBKDF; + +template class Algorithm_Cache; + +class Engine; +class Mutex_Factory; + +/** +* Algorithm Factory +*/ +class BOTAN_DLL Algorithm_Factory + { + public: + /** + * Constructor + * @param mf a mutex factory + */ + Algorithm_Factory(Mutex_Factory& mf); + + /** + * Destructor + */ + ~Algorithm_Factory(); + + /** + * @param engine to add (Algorithm_Factory takes ownership) + */ + void add_engine(Engine* engine); + + /** + * Clear out any cached objects + */ + void clear_caches(); + + /** + * @param algo_spec the algorithm we are querying + * @returns list of providers of this algorithm + */ + std::vector providers_of(const std::string& algo_spec); + + /** + * @param algo_spec the algorithm we are setting a provider for + * @param provider the provider we would like to use + */ + void set_preferred_provider(const std::string& algo_spec, + const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const BlockCipher* + prototype_block_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + BlockCipher* make_block_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_block_cipher(BlockCipher* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const StreamCipher* + prototype_stream_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + StreamCipher* make_stream_cipher(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_stream_cipher(StreamCipher* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const HashFunction* + prototype_hash_function(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + HashFunction* make_hash_function(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_hash_function(HashFunction* algo, const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const MessageAuthenticationCode* + prototype_mac(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + MessageAuthenticationCode* make_mac(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_mac(MessageAuthenticationCode* algo, + const std::string& provider); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to const prototype object, ready to clone(), or NULL + */ + const PBKDF* prototype_pbkdf(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo_spec the algorithm we want + * @param provider the provider we would like to use + * @returns pointer to freshly created instance of the request algorithm + */ + PBKDF* make_pbkdf(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @param algo the algorithm to add + * @param provider the provider of this algorithm + */ + void add_pbkdf(PBKDF* algo, const std::string& provider); + + /** + * An iterator for the engines in this factory + * @deprecated Avoid in new code + */ + class BOTAN_DLL Engine_Iterator + { + public: + /** + * @return next engine in the sequence + */ + Engine* next() { return af.get_engine_n(n++); } + + /** + * @param a an algorithm factory + */ + Engine_Iterator(const Algorithm_Factory& a) : + af(a) { n = 0; } + private: + const Algorithm_Factory& af; + size_t n; + }; + friend class Engine_Iterator; + + private: + Algorithm_Factory(const Algorithm_Factory&) {} + Algorithm_Factory& operator=(const Algorithm_Factory&) + { return (*this); } + + Engine* get_engine_n(size_t n) const; + + std::vector engines; + + Algorithm_Cache* block_cipher_cache; + Algorithm_Cache* stream_cipher_cache; + Algorithm_Cache* hash_cache; + Algorithm_Cache* mac_cache; + Algorithm_Cache* pbkdf_cache; + }; + +} + + + +namespace Botan { + +class Mutex; + +/** +* Global state container aka the buritto at the center of it all +*/ +class BOTAN_DLL Library_State + { + public: + Library_State(); + ~Library_State(); + + /** + * @param thread_safe should a mutex be used for serialization + */ + void initialize(bool thread_safe); + + /** + * @return global Algorithm_Factory + */ + Algorithm_Factory& algorithm_factory() const; + + /** + * @return global RandomNumberGenerator + */ + RandomNumberGenerator& global_rng(); + + /** + * @param name the name of the allocator + * @return allocator matching this name, or NULL + */ + Allocator* get_allocator(const std::string& name = "") const; + + /** + * Add a new allocator to the list of available ones + * @param alloc the allocator to add + */ + void add_allocator(Allocator* alloc); + + /** + * Set the default allocator + * @param name the name of the allocator to use as the default + */ + void set_default_allocator(const std::string& name); + + /** + * Get a parameter value as std::string. + * @param section the section of the desired key + * @param key the desired keys name + * @result the value of the parameter + */ + std::string get(const std::string& section, + const std::string& key) const; + + /** + * Check whether a certain parameter is set or not. + * @param section the section of the desired key + * @param key the desired keys name + * @result true if the parameters value is set, + * false otherwise + */ + bool is_set(const std::string& section, + const std::string& key) const; + + /** + * Set a configuration parameter. + * @param section the section of the desired key + * @param key the desired keys name + * @param value the new value + * @param overwrite if set to true, the parameters value + * will be overwritten even if it is already set, otherwise + * no existing values will be overwritten. + */ + void set(const std::string& section, + const std::string& key, + const std::string& value, + bool overwrite = true); + + /** + * Add a parameter value to the "alias" section. + * @param key the name of the parameter which shall have a new alias + * @param value the new alias + */ + void add_alias(const std::string& key, + const std::string& value); + + /** + * Resolve an alias. + * @param alias the alias to resolve. + * @return what the alias stands for + */ + std::string deref_alias(const std::string& alias) const; + + /** + * @return newly created Mutex (free with delete) + */ + Mutex* get_mutex() const; + private: + static RandomNumberGenerator* make_global_rng(Algorithm_Factory& af, + Mutex* mutex); + + void load_default_config(); + + Library_State(const Library_State&) {} + Library_State& operator=(const Library_State&) { return (*this); } + + class Mutex_Factory* mutex_factory; + + Mutex* global_rng_lock; + RandomNumberGenerator* global_rng_ptr; + + Mutex* config_lock; + std::map config; + + Mutex* allocator_lock; + std::string default_allocator_name; + std::map alloc_factory; + mutable Allocator* cached_default_allocator; + std::vector allocators; + + Algorithm_Factory* m_algorithm_factory; + }; + +} + + + +namespace Botan { + +/** +* BitBucket is a filter which simply discards all inputs +*/ +struct BOTAN_DLL BitBucket : public Filter + { + void write(const byte[], size_t) {} + + std::string name() const { return "BitBucket"; } + }; + +/** +* This class represents Filter chains. A Filter chain is an ordered +* concatenation of Filters, the input to a Chain sequentially passes +* through all the Filters contained in the Chain. +*/ + +class BOTAN_DLL Chain : public Fanout_Filter + { + public: + void write(const byte input[], size_t length) { send(input, length); } + + std::string name() const; + + /** + * Construct a chain of up to four filters. The filters are set + * up in the same order as the arguments. + */ + Chain(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + + /** + * Construct a chain from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Chain(Filter* filter_arr[], size_t length); + }; + +/** +* This class represents a fork filter, whose purpose is to fork the +* flow of data. It causes an input message to result in n messages at +* the end of the filter, where n is the number of forks. +*/ +class BOTAN_DLL Fork : public Fanout_Filter + { + public: + void write(const byte input[], size_t length) { send(input, length); } + void set_port(size_t n) { Fanout_Filter::set_port(n); } + + std::string name() const; + + /** + * Construct a Fork filter with up to four forks. + */ + Fork(Filter*, Filter*, Filter* = 0, Filter* = 0); + + /** + * Construct a Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Fork(Filter* filter_arr[], size_t length); + }; + +} + + +namespace Botan { + +/** +* This class represents keyed filters, i.e. filters that have to be +* fed with a key in order to function. +*/ +class BOTAN_DLL Keyed_Filter : public Filter + { + public: + /** + * Set the key of this filter + * @param key the key to use + */ + virtual void set_key(const SymmetricKey& key) = 0; + + /** + * Set the initialization vector of this filter. Note: you should + * call set_iv() only after you have called set_key() + * @param iv the initialization vector to use + */ + virtual void set_iv(const InitializationVector& iv); + + /** + * Check whether a key length is valid for this filter + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + virtual bool valid_keylength(size_t length) const = 0; + + /** + * Check whether an IV length is valid for this filter + * @param length the IV length to be checked for validity + * @return true if the IV length is valid, false otherwise + */ + virtual bool valid_iv_length(size_t length) const + { return (length == 0); } + }; + +} + + +namespace Botan { + +/** +* This class represents abstract data sink objects. +*/ +class BOTAN_DLL DataSink : public Filter + { + public: + bool attachable() { return false; } + DataSink() {} + virtual ~DataSink() {} + private: + DataSink& operator=(const DataSink&) { return (*this); } + DataSink(const DataSink&); + }; + +/** +* This class represents a data sink which writes its output to a stream. +*/ +class BOTAN_DLL DataSink_Stream : public DataSink + { + public: + std::string name() const { return identifier; } + + void write(const byte[], size_t); + + /** + * Construct a DataSink_Stream from a stream. + * @param stream the stream to write to + * @param name identifier + */ + DataSink_Stream(std::ostream& stream, + const std::string& name = ""); + + /** + * Construct a DataSink_Stream from a stream. + * @param pathname the name of the file to open a stream to + * @param use_binary indicates whether to treat the file + * as a binary file or not + */ + DataSink_Stream(const std::string& pathname, + bool use_binary = false); + + ~DataSink_Stream(); + private: + const std::string identifier; + + std::ostream* sink_p; + std::ostream& sink; + }; + +} + + + +#if defined(BOTAN_HAS_CODEC_FILTERS) + +namespace Botan { + +/** +* This class represents a Base64 encoder. +*/ +class BOTAN_DLL Base64_Encoder : public Filter + { + public: + std::string name() const { return "Base64_Encoder"; } + + /** + * Input a part of a message to the encoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const byte input[], size_t length); + + /** + * Inform the Encoder that the current message shall be closed. + */ + void end_msg(); + + /** + * Create a base64 encoder. + * @param breaks whether to use line breaks in the output + * @param length the length of the lines of the output + * @param t_n whether to use a trailing newline + */ + Base64_Encoder(bool breaks = false, size_t length = 72, + bool t_n = false); + private: + void encode_and_send(const byte input[], size_t length, + bool final_inputs = false); + void do_output(const byte output[], size_t length); + + const size_t line_length; + const bool trailing_newline; + MemoryVector in, out; + size_t position, out_position; + }; + +/** +* This object represents a Base64 decoder. +*/ +class BOTAN_DLL Base64_Decoder : public Filter + { + public: + std::string name() const { return "Base64_Decoder"; } + + /** + * Input a part of a message to the decoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const byte input[], size_t length); + + /** + * Finish up the current message + */ + void end_msg(); + + /** + * Create a base64 decoder. + * @param checking the type of checking that shall be performed by + * the decoder + */ + Base64_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking checking; + MemoryVector in, out; + size_t position; + }; + +} + + +namespace Botan { + +/** +* Converts arbitrary binary data to hex strings, optionally with +* newlines inserted +*/ +class BOTAN_DLL Hex_Encoder : public Filter + { + public: + /** + * Whether to use uppercase or lowercase letters for the encoded string. + */ + enum Case { Uppercase, Lowercase }; + + std::string name() const { return "Hex_Encoder"; } + + void write(const byte in[], size_t length); + void end_msg(); + + /** + * Create a hex encoder. + * @param the_case the case to use in the encoded strings. + */ + Hex_Encoder(Case the_case); + + /** + * Create a hex encoder. + * @param newlines should newlines be used + * @param line_length if newlines are used, how long are lines + * @param the_case the case to use in the encoded strings + */ + Hex_Encoder(bool newlines = false, + size_t line_length = 72, + Case the_case = Uppercase); + private: + void encode_and_send(const byte[], size_t); + + const Case casing; + const size_t line_length; + MemoryVector in, out; + size_t position, counter; + }; + +/** +* Converts hex strings to bytes +*/ +class BOTAN_DLL Hex_Decoder : public Filter + { + public: + std::string name() const { return "Hex_Decoder"; } + + void write(const byte[], size_t); + void end_msg(); + + /** + * Construct a Hex Decoder using the specified + * character checking. + * @param checking the checking to use during decoding. + */ + Hex_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking checking; + MemoryVector in, out; + size_t position; + }; + +} + +#endif + +namespace Botan { + +/** +* Stream Cipher Filter. +*/ +class BOTAN_DLL StreamCipher_Filter : public Keyed_Filter + { + public: + + std::string name() const { return cipher->name(); } + + /** + * Write input data + * @param input data + * @param input_len length of input in bytes + */ + void write(const byte input[], size_t input_len); + + bool valid_iv_length(size_t iv_len) const + { return cipher->valid_iv_length(iv_len); } + + /** + * Set the initialization vector for this filter. + * @param iv the initialization vector to set + */ + void set_iv(const InitializationVector& iv); + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + /** + * Check whether a key length is valid for this filter. + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + bool valid_keylength(size_t length) const + { return cipher->valid_keylength(length); } + + /** + * Construct a stream cipher filter. + * @param cipher_obj a cipher object to use + */ + StreamCipher_Filter(StreamCipher* cipher_obj); + + /** + * Construct a stream cipher filter. + * @param cipher_obj a cipher object to use + * @param key the key to use inside this filter + */ + StreamCipher_Filter(StreamCipher* cipher_obj, const SymmetricKey& key); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + */ + StreamCipher_Filter(const std::string& cipher); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + * @param key the key to use inside this filter + */ + StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key); + + ~StreamCipher_Filter() { delete cipher; } + private: + SecureVector buffer; + StreamCipher* cipher; + }; + +/** +* Hash Filter. +*/ +class BOTAN_DLL Hash_Filter : public Filter + { + public: + void write(const byte input[], size_t len) { hash->update(input, len); } + void end_msg(); + + std::string name() const { return hash->name(); } + + /** + * Construct a hash filter. + * @param hash_fun the hash function to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(HashFunction* hash_fun, size_t len = 0) : + OUTPUT_LENGTH(len), hash(hash_fun) {} + + /** + * Construct a hash filter. + * @param request the name of the hash algorithm to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(const std::string& request, size_t len = 0); + + ~Hash_Filter() { delete hash; } + private: + const size_t OUTPUT_LENGTH; + HashFunction* hash; + }; + +/** +* MessageAuthenticationCode Filter. +*/ +class BOTAN_DLL MAC_Filter : public Keyed_Filter + { + public: + void write(const byte input[], size_t len) { mac->update(input, len); } + void end_msg(); + + std::string name() const { return mac->name(); } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) { mac->set_key(key); } + + /** + * Check whether a key length is valid for this filter. + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + bool valid_keylength(size_t length) const + { return mac->valid_keylength(length); } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac_obj the MAC to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + size_t out_len = 0) : OUTPUT_LENGTH(out_len) + { + mac = mac_obj; + } + + /** + * Construct a MAC filter. + * @param mac_obj the MAC to use + * @param key the MAC key to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + const SymmetricKey& key, + size_t out_len = 0) : OUTPUT_LENGTH(out_len) + { + mac = mac_obj; + mac->set_key(key); + } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the name of the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, size_t len = 0); + + /** + * Construct a MAC filter. + * @param mac the name of the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, const SymmetricKey& key, + size_t len = 0); + + ~MAC_Filter() { delete mac; } + private: + const size_t OUTPUT_LENGTH; + MessageAuthenticationCode* mac; + }; + +} + + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_DLL BlockCipherModePaddingMethod + { + public: + /** + * @param block output buffer + * @param size of the block + * @param current_position in the last block + */ + virtual void pad(byte block[], + size_t size, + size_t current_position) const = 0; + + /** + * @param block the last block + * @param size the of the block + */ + virtual size_t unpad(const byte block[], + size_t size) const = 0; + + /** + * @param block_size of the cipher + * @param position in the current block + * @return number of padding bytes that will be appended + */ + virtual size_t pad_bytes(size_t block_size, + size_t position) const; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(size_t block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() {} + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_DLL PKCS7_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], size_t, size_t) const; + size_t unpad(const byte[], size_t) const; + bool valid_blocksize(size_t) const; + std::string name() const { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_DLL ANSI_X923_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], size_t, size_t) const; + size_t unpad(const byte[], size_t) const; + bool valid_blocksize(size_t) const; + std::string name() const { return "X9.23"; } + }; + +/** +* One And Zeros Padding +*/ +class BOTAN_DLL OneAndZeros_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], size_t, size_t) const; + size_t unpad(const byte[], size_t) const; + bool valid_blocksize(size_t) const; + std::string name() const { return "OneAndZeros"; } + }; + +/** +* Null Padding +*/ +class BOTAN_DLL Null_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], size_t, size_t) const { return; } + size_t unpad(const byte[], size_t size) const { return size; } + size_t pad_bytes(size_t, size_t) const { return 0; } + bool valid_blocksize(size_t) const { return true; } + std::string name() const { return "NoPadding"; } + }; + +} + + +namespace Botan { + +/** +* Key Derivation Function +*/ +class BOTAN_DLL KDF : public Algorithm + { + public: + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + */ + SecureVector derive_key(size_t key_len, + const MemoryRegion& secret, + const std::string& salt = "") const; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + */ + SecureVector derive_key(size_t key_len, + const MemoryRegion& secret, + const MemoryRegion& salt) const; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param salt_len size of salt in bytes + */ + SecureVector derive_key(size_t key_len, + const MemoryRegion& secret, + const byte salt[], + size_t salt_len) const; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + */ + SecureVector derive_key(size_t key_len, + const byte secret[], + size_t secret_len, + const std::string& salt = "") const; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + */ + SecureVector derive_key(size_t key_len, + const byte secret[], + size_t secret_len, + const byte salt[], + size_t salt_len) const; + + void clear() {} + + virtual KDF* clone() const = 0; + private: + virtual SecureVector + derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const = 0; + }; + +/** +* Mask Generation Function +*/ +class BOTAN_DLL MGF + { + public: + virtual void mask(const byte in[], size_t in_len, + byte out[], size_t out_len) const = 0; + + virtual ~MGF() {} + }; + +} + + +namespace Botan { + +/** +* Encoding Method for Encryption +*/ +class BOTAN_DLL EME + { + public: + /** + * Return the maximum input size in bytes we can support + * @param keybits the size of the key in bits + * @return upper bound of input in bytes + */ + virtual size_t maximum_input_size(size_t keybits) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + SecureVector encode(const byte in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Encode an input + * @param in the plaintext + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + SecureVector encode(const MemoryRegion& in, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Decode an input + * @param in the encoded plaintext + * @param in_length length of encoded plaintext in bytes + * @param key_length length of the key in bits + * @return plaintext + */ + SecureVector decode(const byte in[], + size_t in_length, + size_t key_length) const; + + /** + * Decode an input + * @param in the encoded plaintext + * @param key_length length of the key in bits + * @return plaintext + */ + SecureVector decode(const MemoryRegion& in, + size_t key_length) const; + + virtual ~EME() {} + private: + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + virtual SecureVector pad(const byte in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const = 0; + + /** + * Decode an input + * @param in the encoded plaintext + * @param in_length length of encoded plaintext in bytes + * @param key_length length of the key in bits + * @return plaintext + */ + virtual SecureVector unpad(const byte in[], + size_t in_length, + size_t key_length) const = 0; + }; + +} + + +namespace Botan { + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const BlockCipher* +retrieve_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_block_cipher(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const StreamCipher* +retrieve_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_stream_cipher(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const HashFunction* +retrieve_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_hash_function(algo_spec); + } + +/** +* Retrieve an object prototype from the global factory +* @param algo_spec an algorithm name +* @return constant prototype object (use clone to create usable object), + library retains ownership +*/ +inline const MessageAuthenticationCode* +retrieve_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.prototype_mac(algo_spec); + } + +/* +* Get an algorithm object +* NOTE: these functions create and return new objects, letting the +* caller assume ownership of them +*/ + +/** +* Block cipher factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired block cipher +* @return pointer to the block cipher object +*/ +inline BlockCipher* get_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_block_cipher(algo_spec); + } + +/** +* Stream cipher factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired stream cipher +* @return pointer to the stream cipher object +*/ +inline StreamCipher* get_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_stream_cipher(algo_spec); + } + +/** +* Hash function factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired hash function +* @return pointer to the hash function object +*/ +inline HashFunction* get_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_hash_function(algo_spec); + } + +/** +* MAC factory method. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the desired MAC +* @return pointer to the MAC object +*/ +inline MessageAuthenticationCode* get_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return af.make_mac(algo_spec); + } + +/** +* Password based key derivation function factory method +* @param algo_spec the name of the desired PBKDF algorithm +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL PBKDF* get_pbkdf(const std::string& algo_spec); + +/** +* @deprecated Use get_pbkdf +* @param algo_spec the name of the desired algorithm +* @return pointer to newly allocated object of that type +*/ +inline PBKDF* get_s2k(const std::string& algo_spec) + { + return get_pbkdf(algo_spec); + } + +/* +* Get an EMSA/EME/KDF/MGF function +*/ +// NOTE: these functions create and return new objects, letting the +// caller assume ownership of them + +/** +* Factory method for EME (message-encoding methods for encryption) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL EME* get_eme(const std::string& algo_spec); + +/** +* Factory method for EMSA (message-encoding methods for signatures +* with appendix) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL EMSA* get_emsa(const std::string& algo_spec); + +/** +* Factory method for KDF (key derivation function) +* @param algo_spec the name of the KDF to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL KDF* get_kdf(const std::string& algo_spec); + +/* +* Get a cipher object +*/ + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param iv the initialization vector to be used +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to newly allocated encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. No key will be +* set in the filter. +* +* @param algo_spec the name of the desired cipher +* @param direction determines whether the filter will be an encrypting or +* decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_DLL Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction); + +/** +* Check if an algorithm exists. +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +BOTAN_DLL bool have_algorithm(const std::string& algo_spec); + +/** +* Check if a block cipher algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_block_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_block_cipher(algo_spec) != 0); + } + +/** +* Check if a stream cipher algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_stream_cipher(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_stream_cipher(algo_spec) != 0); + } + +/** +* Check if a hash algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_hash(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_hash_function(algo_spec) != 0); + } + +/** +* Check if a MAC algorithm exists. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm to check for +* @return true if the algorithm exists, false otherwise +*/ +inline bool have_mac(const std::string& algo_spec) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + return (af.prototype_mac(algo_spec) != 0); + } + +/* +* Query information about an algorithm +*/ + +/** +* Find out the block size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return block size of the specified algorithm +*/ +BOTAN_DLL size_t block_size_of(const std::string& algo_spec); + +/** +* Find out the output length of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return output length of the specified algorithm +*/ +BOTAN_DLL size_t output_length_of(const std::string& algo_spec); + +/** +* Find out the minimum key size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return minimum key length of the specified algorithm +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t min_keylength_of(const std::string& algo_spec); + +/** +* Find out the maximum key size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return maximum key length of the specified algorithm +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t max_keylength_of(const std::string& algo_spec); + +/** +* Find out the size any valid key is a multiple of for a certain algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return size any valid key is a multiple of +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t keylength_multiple_of(const std::string& algo_spec); + +} + + +namespace Botan { + +/* +* Get information describing the version +*/ + +/** +* Get a human-readable string identifying the version of Botan. +* No particular format should be assumed. +* @return version string +*/ +BOTAN_DLL std::string version_string(); + +/** +* Return the date this version of botan was released, in an integer of +* the form YYYYMMDD. For instance a version released on May 21, 2013 +* would return the integer 20130521. If the currently running version +* is not an official release, this function will return 0 instead. +* +* @return release date, or zero if unreleased +*/ +BOTAN_DLL u32bit version_datestamp(); + +/** +* Get the major version number. +* @return major version number +*/ +BOTAN_DLL u32bit version_major(); + +/** +* Get the minor version number. +* @return minor version number +*/ +BOTAN_DLL u32bit version_minor(); + +/** +* Get the patch number. +* @return patch number +*/ +BOTAN_DLL u32bit version_patch(); + +/* +* Macros for compile-time version checks +*/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +/** +* Compare using BOTAN_VERSION_CODE_FOR, as in +* # if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,8,0) +* # error "Botan version too old" +* # endif +*/ +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + + + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + +namespace Botan { + +/** +* An automatically seeded PRNG +*/ +class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator + { + public: + void randomize(byte out[], size_t len) + { rng->randomize(out, len); } + + bool is_seeded() const { return rng->is_seeded(); } + + void clear() { rng->clear(); } + + std::string name() const { return rng->name(); } + + void reseed(size_t poll_bits = 256) { rng->reseed(poll_bits); } + + void add_entropy_source(EntropySource* es) + { rng->add_entropy_source(es); } + + void add_entropy(const byte in[], size_t len) + { rng->add_entropy(in, len); } + + AutoSeeded_RNG() { rng = &global_state().global_rng(); } + private: + RandomNumberGenerator* rng; + }; + +} + +#endif + + +namespace Botan { + +/** +* PKCS #10 Certificate Request. +*/ +class BOTAN_DLL PKCS10_Request : public X509_Object + { + public: + /** + * Get the subject public key. + * @return subject public key + */ + Public_Key* subject_public_key() const; + + /** + * Get the raw DER encoded public key. + * @return raw DER encoded public key + */ + MemoryVector raw_public_key() const; + + /** + * Get the subject DN. + * @return subject DN + */ + X509_DN subject_dn() const; + + /** + * Get the subject alternative name. + * @return subject alternative name. + */ + AlternativeName subject_alt_name() const; + + /** + * Get the key constraints for the key associated with this + * PKCS#10 object. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the extendend key constraints (if any). + * @return extended key constraints + */ + std::vector ex_constraints() const; + + /** + * Find out whether this is a CA request. + * @result true if it is a CA request, false otherwise. + */ + bool is_CA() const; + + /** + * Return the constraint on the path length defined + * in the BasicConstraints extension. + * @return path limit + */ + u32bit path_limit() const; + + /** + * Get the challenge password for this request + * @return challenge password for this request + */ + std::string challenge_password() const; + + /** + * Create a PKCS#10 Request from a data source. + * @param source the data source providing the DER encoded request + */ + PKCS10_Request(DataSource& source); + + /** + * Create a PKCS#10 Request from a file. + * @param filename the name of the file containing the DER or PEM + * encoded request file + */ + PKCS10_Request(const std::string& filename); + private: + void force_decode(); + void handle_attribute(const Attribute&); + + Data_Store info; + }; + +} + + +namespace Botan { + +/** +* Options for X.509 certificates. +*/ +class BOTAN_DLL X509_Cert_Options + { + public: + /** + * the subject common name + */ + std::string common_name; + + /** + * the subject counry + */ + std::string country; + + /** + * the subject organization + */ + std::string organization; + + /** + * the subject organizational unit + */ + std::string org_unit; + + /** + * the subject locality + */ + std::string locality; + + /** + * the subject state + */ + std::string state; + + /** + * the subject serial number + */ + std::string serial_number; + + /** + * the subject email adress + */ + std::string email; + + /** + * the subject URI + */ + std::string uri; + + /** + * the subject IPv4 address + */ + std::string ip; + + /** + * the subject DNS + */ + std::string dns; + + /** + * the subject XMPP + */ + std::string xmpp; + + /** + * the subject challenge password + */ + std::string challenge; + + /** + * the subject notBefore + */ + X509_Time start; + /** + * the subject notAfter + */ + X509_Time end; + + /** + * Indicates whether the certificate request + */ + bool is_CA; + + /** + * Indicates the BasicConstraints path limit + */ + size_t path_limit; + + /** + * The key constraints for the subject public key + */ + Key_Constraints constraints; + + /** + * The key extended constraints for the subject public key + */ + std::vector ex_constraints; + + /** + * Check the options set in this object for validity. + */ + void sanity_check() const; + + /** + * Mark the certificate as a CA certificate and set the path limit. + * @param limit the path limit to be set in the BasicConstraints extension. + */ + void CA_key(size_t limit = 1); + + /** + * Set the notBefore of the certificate. + * @param time the notBefore value of the certificate + */ + void not_before(const std::string& time); + + /** + * Set the notAfter of the certificate. + * @param time the notAfter value of the certificate + */ + void not_after(const std::string& time); + + /** + * Add the key constraints of the KeyUsage extension. + * @param constr the constraints to set + */ + void add_constraints(Key_Constraints constr); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param oid the oid to add + */ + void add_ex_constraint(const OID& oid); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param name the name to look up the oid to add + */ + void add_ex_constraint(const std::string& name); + + /** + * Construct a new options object + * @param opts define the common name of this object. An example for this + * parameter would be "common_name/country/organization/organizational_unit". + * @param expire_time the expiration time (from the current clock in seconds) + */ + X509_Cert_Options(const std::string& opts = "", + u32bit expire_time = 365 * 24 * 60 * 60); + }; + +namespace X509 { + +/** +* Create a self-signed X.509 certificate. +* @param opts the options defining the certificate to create +* @param key the private key used for signing, i.e. the key +* associated with this self-signed certificate +* @param hash_fn the hash function to use +* @param rng the rng to use +* @return newly created self-signed certificate +*/ +BOTAN_DLL X509_Certificate +create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +/** +* Create a PKCS#10 certificate request. +* @param opts the options defining the request to create +* @param key the key used to sign this request +* @param rng the rng to use +* @param hash_fn the hash function to use +* @return newly created PKCS#10 request +*/ +BOTAN_DLL PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +} + +} + + +namespace Botan { + +class BigInt; +class ASN1_Object; + +/** +* General DER Encoding Object +*/ +class BOTAN_DLL DER_Encoder + { + public: + SecureVector get_contents(); + + DER_Encoder& start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag = UNIVERSAL); + DER_Encoder& end_cons(); + + DER_Encoder& start_explicit(u16bit type_tag); + DER_Encoder& end_explicit(); + + DER_Encoder& raw_bytes(const byte val[], size_t len); + DER_Encoder& raw_bytes(const MemoryRegion& val); + + DER_Encoder& encode_null(); + DER_Encoder& encode(bool b); + DER_Encoder& encode(size_t s); + DER_Encoder& encode(const BigInt& n); + DER_Encoder& encode(const MemoryRegion& v, ASN1_Tag real_type); + DER_Encoder& encode(const byte val[], size_t len, ASN1_Tag real_type); + + DER_Encoder& encode(bool b, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(size_t s, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const BigInt& n, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const MemoryRegion& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const byte v[], size_t len, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + template + DER_Encoder& encode_optional(const T& value, const T& default_value) + { + if(value != default_value) + encode(value); + return (*this); + } + + template + DER_Encoder& encode_list(const std::vector& values) + { + for(size_t i = 0; i != values.size(); ++i) + encode(values[i]); + return (*this); + } + + DER_Encoder& encode(const ASN1_Object& obj); + DER_Encoder& encode_if(bool pred, DER_Encoder& enc); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const byte rep[], size_t length); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const MemoryRegion& rep); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& str); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + byte val); + + private: + class DER_Sequence + { + public: + ASN1_Tag tag_of() const; + SecureVector get_contents(); + void add_bytes(const byte[], size_t); + DER_Sequence(ASN1_Tag, ASN1_Tag); + private: + ASN1_Tag type_tag, class_tag; + SecureVector contents; + std::vector< SecureVector > set_contents; + }; + + SecureVector contents; + std::vector subsequences; + }; + +} + + +namespace Botan { + +/** +* EME1, aka OAEP +*/ +class BOTAN_DLL EME1 : public EME + { + public: + size_t maximum_input_size(size_t) const; + + /** + * @param hash object to use for hashing (takes ownership) + * @param P an optional label. Normally empty. + */ + EME1(HashFunction* hash, const std::string& P = ""); + + ~EME1() { delete mgf; } + private: + SecureVector pad(const byte[], size_t, size_t, + RandomNumberGenerator&) const; + SecureVector unpad(const byte[], size_t, size_t) const; + + SecureVector Phash; + MGF* mgf; + }; + +} + + +namespace Botan { + +/** +* The two types of signature format supported by Botan. +*/ +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +/** +* Enum marking if protection against fault attacks should be used +*/ +enum Fault_Protection { + ENABLE_FAULT_PROTECTION, + DISABLE_FAULT_PROTECTION +}; + +/** +* Public Key Encryptor +*/ +class BOTAN_DLL PK_Encryptor + { + public: + + /** + * Encrypt a message. + * @param in the message as a byte array + * @param length the length of the above byte array + * @param rng the random number source to use + * @return encrypted message + */ + SecureVector encrypt(const byte in[], size_t length, + RandomNumberGenerator& rng) const + { + return enc(in, length, rng); + } + + /** + * Encrypt a message. + * @param in the message + * @param rng the random number source to use + * @return encrypted message + */ + SecureVector encrypt(const MemoryRegion& in, + RandomNumberGenerator& rng) const + { + return enc(&in[0], in.size(), rng); + } + + /** + * Return the maximum allowed message size in bytes. + * @return maximum message size in bytes + */ + virtual size_t maximum_input_size() const = 0; + + PK_Encryptor() {} + virtual ~PK_Encryptor() {} + private: + PK_Encryptor(const PK_Encryptor&) {} + PK_Encryptor& operator=(const PK_Encryptor&) { return *this; } + + virtual SecureVector enc(const byte[], size_t, + RandomNumberGenerator&) const = 0; + }; + +/** +* Public Key Decryptor +*/ +class BOTAN_DLL PK_Decryptor + { + public: + /** + * Decrypt a ciphertext. + * @param in the ciphertext as a byte array + * @param length the length of the above byte array + * @return decrypted message + */ + SecureVector decrypt(const byte in[], size_t length) const + { + return dec(in, length); + } + + /** + * Decrypt a ciphertext. + * @param in the ciphertext + * @return decrypted message + */ + SecureVector decrypt(const MemoryRegion& in) const + { + return dec(&in[0], in.size()); + } + + PK_Decryptor() {} + virtual ~PK_Decryptor() {} + private: + PK_Decryptor(const PK_Decryptor&) {} + PK_Decryptor& operator=(const PK_Decryptor&) { return *this; } + + virtual SecureVector dec(const byte[], size_t) const = 0; + }; + +/** +* Public Key Signer. Use the sign_message() functions for small +* messages. Use multiple calls update() to process large messages and +* generate the signature by finally calling signature(). +*/ +class BOTAN_DLL PK_Signer + { + public: + /** + * Sign a message. + * @param in the message to sign as a byte array + * @param length the length of the above byte array + * @param rng the rng to use + * @return signature + */ + SecureVector sign_message(const byte in[], size_t length, + RandomNumberGenerator& rng); + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return signature + */ + SecureVector sign_message(const MemoryRegion& in, + RandomNumberGenerator& rng) + { return sign_message(&in[0], in.size(), rng); } + + /** + * Add a message part (single byte). + * @param in the byte to add + */ + void update(byte in) { update(&in, 1); } + + /** + * Add a message part. + * @param in the message part to add as a byte array + * @param length the length of the above byte array + */ + void update(const byte in[], size_t length); + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const MemoryRegion& in) { update(&in[0], in.size()); } + + /** + * Get the signature of the so far processed message (provided by the + * calls to update()). + * @param rng the rng to use + * @return signature of the total message + */ + SecureVector signature(RandomNumberGenerator& rng); + + /** + * Set the output format of the signature. + * @param format the signature format to use + */ + void set_output_format(Signature_Format format) { sig_format = format; } + + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + * @param prot says if fault protection should be enabled + */ + PK_Signer(const Private_Key& key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + Fault_Protection prot = ENABLE_FAULT_PROTECTION); + + ~PK_Signer() { delete op; delete verify_op; delete emsa; } + private: + bool self_test_signature(const MemoryRegion& msg, + const MemoryRegion& sig) const; + + PK_Signer(const PK_Signer&) {} + PK_Signer& operator=(const PK_Signer&) { return *this; } + + PK_Ops::Signature* op; + PK_Ops::Verification* verify_op; + EMSA* emsa; + Signature_Format sig_format; + }; + +/** +* Public Key Verifier. Use the verify_message() functions for small +* messages. Use multiple calls update() to process large messages and +* verify the signature by finally calling check_signature(). +*/ +class BOTAN_DLL PK_Verifier + { + public: + /** + * Verify a signature. + * @param msg the message that the signature belongs to, as a byte array + * @param msg_length the length of the above byte array msg + * @param sig the signature as a byte array + * @param sig_length the length of the above byte array sig + * @return true if the signature is valid + */ + bool verify_message(const byte msg[], size_t msg_length, + const byte sig[], size_t sig_length); + /** + * Verify a signature. + * @param msg the message that the signature belongs to + * @param sig the signature + * @return true if the signature is valid + */ + bool verify_message(const MemoryRegion& msg, + const MemoryRegion& sig) + { + return verify_message(&msg[0], msg.size(), + &sig[0], sig.size()); + } + + /** + * Add a message part (single byte) of the message corresponding to the + * signature to be verified. + * @param in the byte to add + */ + void update(byte in) { update(&in, 1); } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part as a byte array + * @param length the length of the above byte array + */ + void update(const byte msg_part[], size_t length); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param in the new message part + */ + void update(const MemoryRegion& in) + { update(&in[0], in.size()); } + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified as a byte array + * @param length the length of the above byte array + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const byte sig[], size_t length); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const MemoryRegion& sig) + { + return check_signature(&sig[0], sig.size()); + } + + /** + * Set the format of the signatures fed to this verifier. + * @param format the signature format to use + */ + void set_input_format(Signature_Format format); + + /** + * Construct a PK Verifier. + * @param pub_key the public key to verify against + * @param emsa the EMSA to use (eg "EMSA3(SHA-1)") + * @param format the signature format to use + */ + PK_Verifier(const Public_Key& pub_key, + const std::string& emsa, + Signature_Format format = IEEE_1363); + + ~PK_Verifier() { delete op; delete emsa; } + private: + PK_Verifier(const PK_Verifier&) {} + PK_Verifier& operator=(const PK_Verifier&) { return *this; } + + bool validate_signature(const MemoryRegion& msg, + const byte sig[], size_t sig_len); + + PK_Ops::Verification* op; + EMSA* emsa; + Signature_Format sig_format; + }; + +/** +* Key used for key agreement +*/ +class BOTAN_DLL PK_Key_Agreement + { + public: + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const byte in[], + size_t in_len, + const byte params[], + size_t params_len) const; + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const MemoryRegion& in, + const byte params[], + size_t params_len) const + { + return derive_key(key_len, &in[0], in.size(), + params, params_len); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const byte in[], size_t in_len, + const std::string& params = "") const + { + return derive_key(key_len, in, in_len, + reinterpret_cast(params.data()), + params.length()); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const MemoryRegion& in, + const std::string& params = "") const + { + return derive_key(key_len, &in[0], in.size(), + reinterpret_cast(params.data()), + params.length()); + } + + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + */ + PK_Key_Agreement(const PK_Key_Agreement_Key& key, + const std::string& kdf); + + ~PK_Key_Agreement() { delete op; delete kdf; } + private: + PK_Key_Agreement(const PK_Key_Agreement_Key&) {} + PK_Key_Agreement& operator=(const PK_Key_Agreement&) { return *this; } + + PK_Ops::Key_Agreement* op; + KDF* kdf; + }; + +/** +* Encryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Encryptor_EME : public PK_Encryptor + { + public: + size_t maximum_input_size() const; + + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param eme the EME to use + */ + PK_Encryptor_EME(const Public_Key& key, + const std::string& eme); + + ~PK_Encryptor_EME() { delete op; delete eme; } + private: + SecureVector enc(const byte[], size_t, + RandomNumberGenerator& rng) const; + + PK_Ops::Encryption* op; + const EME* eme; + }; + +/** +* Decryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Decryptor_EME : public PK_Decryptor + { + public: + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param eme the EME to use + */ + PK_Decryptor_EME(const Private_Key& key, + const std::string& eme); + + ~PK_Decryptor_EME() { delete op; delete eme; } + private: + SecureVector dec(const byte[], size_t) const; + + PK_Ops::Decryption* op; + const EME* eme; + }; + +/* +* Typedefs for compatability with 1.8 +*/ +typedef PK_Encryptor_EME PK_Encryptor_MR_with_EME; +typedef PK_Decryptor_EME PK_Decryptor_MR_with_EME; + +} + + +namespace Botan { + +/** +* DES +*/ +class BOTAN_DLL DES : public Block_Cipher_Fixed_Params<8, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(round_key); } + std::string name() const { return "DES"; } + BlockCipher* clone() const { return new DES; } + + DES() : round_key(32) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector round_key; + }; + +/** +* Triple DES +*/ +class BOTAN_DLL TripleDES : public Block_Cipher_Fixed_Params<8, 16, 24, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(round_key); } + std::string name() const { return "TripleDES"; } + BlockCipher* clone() const { return new TripleDES; } + + TripleDES() : round_key(96) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector round_key; + }; + +/* +* DES Tables +*/ +extern const u32bit DES_SPBOX1[256]; +extern const u32bit DES_SPBOX2[256]; +extern const u32bit DES_SPBOX3[256]; +extern const u32bit DES_SPBOX4[256]; +extern const u32bit DES_SPBOX5[256]; +extern const u32bit DES_SPBOX6[256]; +extern const u32bit DES_SPBOX7[256]; +extern const u32bit DES_SPBOX8[256]; + +extern const u64bit DES_IPTAB1[256]; +extern const u64bit DES_IPTAB2[256]; +extern const u64bit DES_FPTAB1[256]; +extern const u64bit DES_FPTAB2[256]; + +} + + +namespace Botan { + +/** +* DESX +*/ +class BOTAN_DLL DESX : public Block_Cipher_Fixed_Params<8, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { des.clear(); zeroise(K1); zeroise(K2); } + std::string name() const { return "DESX"; } + BlockCipher* clone() const { return new DESX; } + + DESX() : K1(8), K2(8) {} + private: + void key_schedule(const byte[], size_t); + SecureVector K1, K2; + DES des; + }; + +} + + +namespace Botan { + +/** +* The GOST 28147-89 block cipher uses a set of 4 bit Sboxes, however +* the standard does not actually define these Sboxes; they are +* considered a local configuration issue. Several different sets are +* used. +*/ +class BOTAN_DLL GOST_28147_89_Params + { + public: + /** + * @param row the row + * @param col the column + * @return sbox entry at this row/column + */ + byte sbox_entry(size_t row, size_t col) const; + + /** + * @return name of this parameter set + */ + std::string param_name() const { return name; } + + /** + * Default GOST parameters are the ones given in GOST R 34.11 for + * testing purposes; these sboxes are also used by Crypto++, and, + * at least according to Wikipedia, the Central Bank of Russian + * Federation + * @param name of the parameter set + */ + GOST_28147_89_Params(const std::string& name = "R3411_94_TestParam"); + private: + const byte* sboxes; + std::string name; + }; + +/** +* GOST 28147-89 +*/ +class BOTAN_DLL GOST_28147_89 : public Block_Cipher_Fixed_Params<8, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); } + + std::string name() const; + BlockCipher* clone() const { return new GOST_28147_89(SBOX); } + + /** + * @param params the sbox parameters to use + */ + GOST_28147_89(const GOST_28147_89_Params& params); + private: + GOST_28147_89(const SecureVector& other_SBOX) : + SBOX(other_SBOX), EK(8) {} + + void key_schedule(const byte[], size_t); + + SecureVector SBOX; + SecureVector EK; + }; + +} + + +namespace Botan { + +/** +* GOST 34.11 +*/ +class BOTAN_DLL GOST_34_11 : public HashFunction + { + public: + std::string name() const { return "GOST-R-34.11-94" ; } + size_t output_length() const { return 32; } + size_t hash_block_size() const { return 32; } + HashFunction* clone() const { return new GOST_34_11; } + + void clear(); + + GOST_34_11(); + private: + void compress_n(const byte input[], size_t blocks); + + void add_data(const byte[], size_t); + void final_result(byte[]); + + GOST_28147_89 cipher; + SecureVector buffer, sum, hash; + size_t position; + u64bit count; + }; + +} + + +namespace Botan { + +/** +* SHA-384 +*/ +class BOTAN_DLL SHA_384 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-384"; } + size_t output_length() const { return 48; } + HashFunction* clone() const { return new SHA_384; } + + void clear(); + + SHA_384() : MDx_HashFunction(128, true, true, 16), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector digest; + }; + +/** +* SHA-512 +*/ +class BOTAN_DLL SHA_512 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-512"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new SHA_512; } + + void clear(); + + SHA_512() : MDx_HashFunction(128, true, true, 16), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector digest; + }; + +} + + +namespace Botan { + +/** +* Password Based Encryption (PBE) Filter. +*/ +class BOTAN_DLL PBE : public Filter + { + public: + /** + * Set this filter's key. + * @param pw the password to be used for the encryption + */ + virtual void set_key(const std::string& pw) = 0; + + /** + * Create a new random salt value and set the default iterations value. + * @param rng a random number generator + */ + virtual void new_params(RandomNumberGenerator& rng) = 0; + + /** + * DER encode the params (the number of iterations and the salt value) + * @return encoded params + */ + virtual MemoryVector encode_params() const = 0; + + /** + * Decode params and use them inside this Filter. + * @param src a data source to read the encoded params from + */ + virtual void decode_params(DataSource& src) = 0; + + /** + * Get this PBE's OID. + * @return object identifier + */ + virtual OID get_oid() const = 0; + }; + +} + + +namespace Botan { + +/** +* KDF1, from IEEE 1363 +*/ +class BOTAN_DLL KDF1 : public KDF + { + public: + SecureVector derive(size_t, + const byte secret[], size_t secret_len, + const byte P[], size_t P_len) const; + + std::string name() const { return "KDF1(" + hash->name() + ")"; } + KDF* clone() const { return new KDF1(hash->clone()); } + + KDF1(HashFunction* h) : hash(h) {} + KDF1(const KDF1& other) : KDF(), hash(other.hash->clone()) {} + + ~KDF1() { delete hash; } + private: + HashFunction* hash; + }; + +} + + +namespace Botan { + +/** +* MISTY1 +*/ +class BOTAN_DLL MISTY1 : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); zeroise(DK); } + std::string name() const { return "MISTY1"; } + BlockCipher* clone() const { return new MISTY1; } + + /** + * @param rounds the number of rounds. Must be 8 with the current + * implementation + */ + MISTY1(size_t rounds = 8); + private: + void key_schedule(const byte[], size_t); + + SecureVector EK, DK; + }; + +} + + +namespace Botan { + +/** +* 32-bit cyclic redundancy check +*/ +class BOTAN_DLL CRC32 : public HashFunction + { + public: + std::string name() const { return "CRC32"; } + size_t output_length() const { return 4; } + HashFunction* clone() const { return new CRC32; } + + void clear() { crc = 0xFFFFFFFF; } + + CRC32() { clear(); } + ~CRC32() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u32bit crc; + }; + +} + + +namespace Botan { + +namespace PEM_Code { + +/* +* PEM Encoding/Decoding +*/ +BOTAN_DLL std::string encode(const byte[], size_t, + const std::string&, size_t = 64); +BOTAN_DLL std::string encode(const MemoryRegion&, + const std::string&, size_t = 64); + +BOTAN_DLL SecureVector decode(DataSource&, std::string&); +BOTAN_DLL SecureVector decode_check_label(DataSource&, + const std::string&); +BOTAN_DLL bool matches(DataSource&, const std::string& = "", + size_t search_range = 4096); + +} + +} + + +namespace Botan { + +/** +* XTEA +*/ +class BOTAN_DLL XTEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); } + std::string name() const { return "XTEA"; } + BlockCipher* clone() const { return new XTEA; } + + XTEA() : EK(64) {} + protected: + /** + * @return const reference to the key schedule + */ + const SecureVector& get_EK() const { return EK; } + + private: + void key_schedule(const byte[], size_t); + SecureVector EK; + }; + +} + + +namespace Botan { + +/** +* KASUMI, the block cipher used in 3G telephony +*/ +class BOTAN_DLL KASUMI : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); } + std::string name() const { return "KASUMI"; } + BlockCipher* clone() const { return new KASUMI; } + + KASUMI() : EK(64) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector EK; + }; + +} + + +namespace Botan { + +/** +* This class represents discrete logarithm groups. It holds a prime p, +* a prime q = (p-1)/2 and g = x^((p-1)/q) mod p. +*/ +class BOTAN_DLL DL_Group + { + public: + /** + * Get the prime p. + * @return prime p + */ + const BigInt& get_p() const; + + /** + * Get the prime q. + * @return prime q + */ + const BigInt& get_q() const; + + /** + * Get the base g. + * @return base g + */ + const BigInt& get_g() const; + + /** + * The DL group encoding format variants. + */ + enum Format { + ANSI_X9_42, + ANSI_X9_57, + PKCS_3, + + DSA_PARAMETERS = ANSI_X9_57, + DH_PARAMETERS = ANSI_X9_42, + X942_DH_PARAMETERS = ANSI_X9_42, + PKCS3_DH_PARAMETERS = PKCS_3 + }; + + /** + * Determine the prime creation for DL groups. + */ + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + /** + * Perform validity checks on the group. + * @param rng the rng to use + * @param strong whether to perform stronger by lengthier tests + * @return true if the object is consistent, false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, bool strong) const; + + /** + * Encode this group into a string using PEM encoding. + * @param format the encoding format + * @return string holding the PEM encoded group + */ + std::string PEM_encode(Format format) const; + + /** + * Encode this group into a string using DER encoding. + * @param format the encoding format + * @return string holding the DER encoded group + */ + SecureVector DER_encode(Format format) const; + + /** + * Decode a DER/BER encoded group into this instance. + * @param src a DataSource providing the encoded group + * @param format the format of the encoded group + */ + void BER_decode(DataSource& src, Format format); + + /** + * Decode a PEM encoded group into this instance. + * @param src a DataSource providing the encoded group + */ + void PEM_decode(DataSource& src); + + /** + * Construct a DL group with uninitialized internal value. + * Use this constructor is you wish to set the groups values + * from a DER or PEM encoded group. + */ + DL_Group(); + + /** + * Construct a DL group that is registered in the configuration. + * @param name the name that is configured in the global configuration + * for the desired group. If no configuration file is specified, + * the default values from the file policy.cpp will be used. For instance, + * use "modp/ietf/768" as name. + */ + DL_Group(const std::string& name); + + /** + * Create a new group randomly. + * @param rng the random number generator to use + * @param type specifies how the creation of primes p and q shall + * be performed. If type=Strong, then p will be determined as a + * safe prime, and q will be chosen as (p-1)/2. If + * type=Prime_Subgroup and qbits = 0, then the size of q will be + * determined according to the estimated difficulty of the DL + * problem. If type=DSA_Kosherizer, DSA primes will be created. + * @param pbits the number of bits of p + * @param qbits the number of bits of q. Leave it as 0 to have + * the value determined according to pbits. + */ + DL_Group(RandomNumberGenerator& rng, PrimeType type, + size_t pbits, size_t qbits = 0); + + /** + * Create a DSA group with a given seed. + * @param rng the random number generator to use + * @param seed the seed to use to create the random primes + * @param pbits the desired bit size of the prime p + * @param qbits the desired bit size of the prime q. + */ + DL_Group(RandomNumberGenerator& rng, const MemoryRegion& seed, + size_t pbits = 1024, size_t qbits = 0); + + /** + * Create a DL group. The prime q will be determined according to p. + * @param p the prime p + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& g); + + /** + * Create a DL group. + * @param p the prime p + * @param q the prime q + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& q, const BigInt& g); + private: + static BigInt make_dsa_generator(const BigInt&, const BigInt&); + + void init_check() const; + void initialize(const BigInt&, const BigInt&, const BigInt&); + bool initialized; + BigInt p, q, g; + }; + +} + + +namespace Botan { + +/** +* This class represents discrete logarithm (DL) public keys. +*/ +class BOTAN_DLL DL_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + AlgorithmIdentifier algorithm_identifier() const; + + MemoryVector x509_subject_public_key() const; + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_domain() const { return group; } + + /** + * Get the public value y with y = g^x mod p where x is the secret key. + */ + const BigInt& get_y() const { return y; } + + /** + * Get the prime p of the underlying DL group. + * @return prime p + */ + const BigInt& group_p() const { return group.get_p(); } + + /** + * Get the prime q of the underlying DL group. + * @return prime q + */ + const BigInt& group_q() const { return group.get_q(); } + + /** + * Get the generator g of the underlying DL group. + * @return generator g + */ + const BigInt& group_g() const { return group.get_g(); } + + /** + * Get the underlying groups encoding format. + * @return encoding format + */ + virtual DL_Group::Format group_format() const = 0; + + DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + DL_Group::Format group_format); + + protected: + DL_Scheme_PublicKey() {} + + /** + * The DL public key + */ + BigInt y; + + /** + * The DL group + */ + DL_Group group; + }; + +/** +* This class represents discrete logarithm (DL) private keys. +*/ +class BOTAN_DLL DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the secret key x. + * @return secret key + */ + const BigInt& get_x() const { return x; } + + MemoryVector pkcs8_private_key() const; + + DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + DL_Group::Format group_format); + + protected: + DL_Scheme_PrivateKey() {} + + /** + * The DL private key + */ + BigInt x; + }; + +} + + +namespace Botan { + +/** +* Modular Reducer (using Barrett's technique) +*/ +class BOTAN_DLL Modular_Reducer + { + public: + const BigInt& get_modulus() const { return modulus; } + + BigInt reduce(const BigInt& x) const; + + /** + * Multiply mod p + * @param x + * @param y + * @return (x * y) % p + */ + BigInt multiply(const BigInt& x, const BigInt& y) const + { return reduce(x * y); } + + /** + * Square mod p + * @param x + * @return (x * x) % p + */ + BigInt square(const BigInt& x) const + { return reduce(Botan::square(x)); } + + /** + * Cube mod p + * @param x + * @return (x * x * x) % p + */ + BigInt cube(const BigInt& x) const + { return multiply(x, this->square(x)); } + + bool initialized() const { return (mod_words != 0); } + + Modular_Reducer() { mod_words = 0; } + Modular_Reducer(const BigInt& mod); + private: + BigInt modulus, modulus_2, mu; + size_t mod_words; + }; + +} + + +namespace Botan { + +/** +* Blinding Function Object +*/ +class BOTAN_DLL Blinder + { + public: + BigInt blind(const BigInt& x) const; + BigInt unblind(const BigInt& x) const; + + bool initialized() const { return reducer.initialized(); } + + Blinder() {} + + /** + * Construct a blinder + * @param mask the forward (blinding) mask + * @param inverse_mask the inverse of mask (depends on algo) + * @param modulus of the group operations are performed in + */ + Blinder(const BigInt& mask, + const BigInt& inverse_mask, + const BigInt& modulus); + + private: + Modular_Reducer reducer; + mutable BigInt e, d; + }; + +} + + +namespace Botan { + +/** +* This class represents Diffie-Hellman public keys. +*/ +class BOTAN_DLL DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DH"; } + + MemoryVector public_value() const; + size_t max_input_bits() const { return group_p().bits(); } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + DH_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) {} + + /** + * Construct a public key with the specified parameters. + * @param grp the DL group to use in the key + * @param y the public value y + */ + DH_PublicKey(const DL_Group& grp, const BigInt& y); + protected: + DH_PublicKey() {} + }; + +/** +* This class represents Diffie-Hellman private keys. +*/ +class BOTAN_DLL DH_PrivateKey : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + MemoryVector public_value() const; + + /** + * Load a DH private key + * @param alg_id the algorithm id + * @param key_bits the subject public key + * @param rng a random number generator + */ + DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng); + + /** + * Construct a private key with predetermined value. + * @param rng random number generator to use + * @param grp the group to be used in the key + * @param x the key's secret value (or if zero, generate a new key) + */ + DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, + const BigInt& x = 0); + }; + +/** +* DH operation +*/ +class BOTAN_DLL DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + DH_KA_Operation(const DH_PrivateKey& key); + + SecureVector agree(const byte w[], size_t w_len); + private: + const BigInt& p; + + Fixed_Exponent_Power_Mod powermod_x_p; + Blinder blinder; + }; + +} + + +namespace Botan { + +/** +* CAST-256 +*/ +class BOTAN_DLL CAST_256 : public Block_Cipher_Fixed_Params<16, 4, 32, 4> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(MK); zeroise(RK); } + std::string name() const { return "CAST-256"; } + BlockCipher* clone() const { return new CAST_256; } + + CAST_256() : MK(48), RK(48) {} + private: + void key_schedule(const byte[], size_t); + + static const u32bit KEY_MASK[192]; + static const byte KEY_ROT[32]; + + SecureVector MK; + SecureVector RK; + }; + +extern const u32bit CAST_SBOX1[256]; +extern const u32bit CAST_SBOX2[256]; +extern const u32bit CAST_SBOX3[256]; +extern const u32bit CAST_SBOX4[256]; + +} + + +namespace Botan { + +/** +* MD2 +*/ +class BOTAN_DLL MD2 : public HashFunction + { + public: + std::string name() const { return "MD2"; } + size_t output_length() const { return 16; } + size_t hash_block_size() const { return 16; } + HashFunction* clone() const { return new MD2; } + + void clear(); + + MD2() : X(48), checksum(16), buffer(16) + { clear(); } + private: + void add_data(const byte[], size_t); + void hash(const byte[]); + void final_result(byte[]); + + SecureVector X, checksum, buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* RC6, Ron Rivest's AES candidate +*/ +class BOTAN_DLL RC6 : public Block_Cipher_Fixed_Params<16, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(S); } + std::string name() const { return "RC6"; } + BlockCipher* clone() const { return new RC6; } + + RC6() : S(44) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector S; + }; + +} + + +namespace Botan { + +/** +* WiderWake4+1-BE +* +* Note: quite old and possibly not safe; use XSalsa20 or a block +* cipher in counter mode. +*/ +class BOTAN_DLL WiderWake_41_BE : public StreamCipher + { + public: + void cipher(const byte[], byte[], size_t); + void set_iv(const byte[], size_t); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == 8); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(16); + } + + void clear(); + std::string name() const { return "WiderWake4+1-BE"; } + StreamCipher* clone() const { return new WiderWake_41_BE; } + + WiderWake_41_BE() : T(256), state(5), t_key(4), + buffer(DEFAULT_BUFFERSIZE), position(0) + {} + + private: + void key_schedule(const byte[], size_t); + + void generate(size_t); + + SecureVector T; + SecureVector state; + SecureVector t_key; + SecureVector buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* ElGamal Public Key +*/ +class BOTAN_DLL ElGamal_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "ElGamal"; } + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + size_t max_input_bits() const { return (group_p().bits() - 1); } + + ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + {} + + ElGamal_PublicKey(const DL_Group& group, const BigInt& y); + protected: + ElGamal_PublicKey() {} + }; + +/** +* ElGamal Private Key +*/ +class BOTAN_DLL ElGamal_PrivateKey : public ElGamal_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng); + + ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& priv_key = 0); + }; + +/** +* ElGamal encryption operation +*/ +class BOTAN_DLL ElGamal_Encryption_Operation : public PK_Ops::Encryption + { + public: + size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; } + + ElGamal_Encryption_Operation(const ElGamal_PublicKey& key); + + SecureVector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + private: + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p; + }; + +/** +* ElGamal decryption operation +*/ +class BOTAN_DLL ElGamal_Decryption_Operation : public PK_Ops::Decryption + { + public: + size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; } + + ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key); + + SecureVector decrypt(const byte msg[], size_t msg_len); + private: + Fixed_Exponent_Power_Mod powermod_x_p; + Modular_Reducer mod_p; + Blinder blinder; + }; + +} + + +namespace Botan { + +/** +HMAC_RNG - based on the design described in "On Extract-then-Expand +Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk +(henceforce, 'E-t-E') + +However it actually can be parameterized with any two MAC functions, +not restricted to HMAC (this variation is also described in Krawczyk's +paper), for instance one could use HMAC(SHA-512) as the extractor +and CMAC(AES-256) as the PRF. +*/ +class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator + { + public: + void randomize(byte buf[], size_t len); + bool is_seeded() const { return seeded; } + void clear(); + std::string name() const; + + void reseed(size_t poll_bits); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte[], size_t); + + /** + * @param extractor a MAC used for extracting the entropy + * @param prf a MAC used as a PRF using HKDF construction + */ + HMAC_RNG(MessageAuthenticationCode* extractor, + MessageAuthenticationCode* prf); + + ~HMAC_RNG(); + private: + MessageAuthenticationCode* extractor; + MessageAuthenticationCode* prf; + + std::vector entropy_sources; + bool seeded; + + SecureVector K, io_buffer; + size_t user_input_len; + u32bit counter; + }; + +} + + +namespace Botan { + +/** +* A MAC only used in SSLv3. Do not use elsewhere! Use HMAC instead. +*/ +class BOTAN_DLL SSL3_MAC : public MessageAuthenticationCode + { + public: + std::string name() const; + size_t output_length() const { return hash->output_length(); } + MessageAuthenticationCode* clone() const; + + void clear(); + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(hash->output_length()); + } + + /** + * @param hash the underlying hash to use + */ + SSL3_MAC(HashFunction* hash); + ~SSL3_MAC() { delete hash; } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + HashFunction* hash; + SecureVector i_key, o_key; + }; + +} + + +namespace Botan { + +/** +EMSA1_BSI is a variant of EMSA1 specified by the BSI. It accepts only +hash values which are less or equal than the maximum key length. The +implementation comes from InSiTo +*/ +class BOTAN_DLL EMSA1_BSI : public EMSA1 + { + public: + /** + * @param hash the hash object to use + */ + EMSA1_BSI(HashFunction* hash) : EMSA1(hash) {} + private: + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + }; + +} + + +namespace Botan { + +/** +* Serpent, an AES finalist +*/ +class BOTAN_DLL Serpent : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(round_key); } + std::string name() const { return "Serpent"; } + BlockCipher* clone() const { return new Serpent; } + + Serpent() : round_key(132) {} + protected: + /** + * For use by subclasses using SIMD, asm, etc + * @return const reference to the key schedule + */ + const SecureVector& get_round_keys() const + { return round_key; } + + /** + * For use by subclasses that implement the key schedule + * @param ks is the new key schedule value to set + */ + void set_round_keys(const u32bit ks[132]) + { + copy_mem(&round_key[0], ks, 132); + } + + private: + void key_schedule(const byte key[], size_t length); + SecureVector round_key; + }; + +} + + +namespace Botan { + +/** +* NIST's SHA-160 +*/ +class BOTAN_DLL SHA_160 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new SHA_160; } + + void clear(); + + SHA_160() : MDx_HashFunction(64, true, true), digest(5), W(80) + { + clear(); + } + protected: + /** + * Set a custom size for the W array. Normally 80, but some + * subclasses need slightly more for best performance/internal + * constraints + * @param W_size how big to make W + */ + SHA_160(size_t W_size) : + MDx_HashFunction(64, true, true), digest(5), W(W_size) + { + clear(); + } + + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + /** + * The digest value, exposed for use by subclasses (asm, SSE2) + */ + SecureVector digest; + + /** + * The message buffer, exposed for use by subclasses (asm, SSE2) + */ + SecureVector W; + }; + +} + + +namespace Botan { + +/** +* ANSI X9.31 RNG +*/ +class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], size_t); + bool is_seeded() const; + void clear(); + std::string name() const; + + void reseed(size_t poll_bits); + void add_entropy_source(EntropySource*); + void add_entropy(const byte[], size_t); + + /** + * @param cipher the block cipher to use in this PRNG + * @param rng the underlying PRNG for generating inputs + * (eg, an HMAC_RNG) + */ + ANSI_X931_RNG(BlockCipher* cipher, + RandomNumberGenerator* rng); + ~ANSI_X931_RNG(); + private: + void rekey(); + void update_buffer(); + + BlockCipher* cipher; + RandomNumberGenerator* prng; + SecureVector V, R; + size_t position; + }; + +} + + +namespace Botan { + +/** +* This class represents ECDSA Public Keys. +*/ +class BOTAN_DLL ECDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + ECDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECDSA") + */ + std::string algo_name() const { return "ECDSA"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + * @result the maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + size_t message_parts() const { return 2; } + + size_t message_part_size() const + { return domain().get_order().bytes(); } + + protected: + ECDSA_PublicKey() {} + }; + +/** +* This class represents ECDSA Private Keys +*/ +class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a ney random key) + */ + ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + bool check_key(RandomNumberGenerator& rng, bool) const; + }; + +/** +* ECDSA signature operation +*/ +class BOTAN_DLL ECDSA_Signature_Operation : public PK_Ops::Signature + { + public: + ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa); + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + private: + const PointGFp& base_point; + const BigInt& order; + const BigInt& x; + Modular_Reducer mod_order; + }; + +/** +* ECDSA verification operation +*/ +class BOTAN_DLL ECDSA_Verification_Operation : public PK_Ops::Verification + { + public: + ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return order.bytes(); } + size_t max_input_bits() const { return order.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const PointGFp& base_point; + const PointGFp& public_point; + const BigInt& order; + }; + +} + + +namespace Botan { + +/** +* BigInt Division +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_DLL divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r); + +} + + +namespace Botan { + +/** +* Square +*/ +class BOTAN_DLL Square : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Square"; } + BlockCipher* clone() const { return new Square; } + + Square() : EK(28), DK(28), ME(32), MD(32) {} + private: + void key_schedule(const byte[], size_t); + + static void transform(u32bit[4]); + + static const byte SE[256]; + static const byte SD[256]; + static const byte Log[256]; + static const byte ALog[255]; + + static const u32bit TE0[256]; + static const u32bit TE1[256]; + static const u32bit TE2[256]; + static const u32bit TE3[256]; + static const u32bit TD0[256]; + static const u32bit TD1[256]; + static const u32bit TD2[256]; + static const u32bit TD3[256]; + + SecureVector EK, DK; + SecureVector ME, MD; + }; + +} + + +namespace Botan { + +/** +* Perform hex encoding +* @param output an array of at least input_length*2 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +*/ +void BOTAN_DLL hex_encode(char output[], + const byte input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_DLL hex_encode(const byte input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_DLL hex_encode(const MemoryRegion& input, + bool uppercase = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL hex_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +SecureVector BOTAN_DLL hex_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +SecureVector BOTAN_DLL hex_decode(const std::string& input, + bool ignore_ws = true); + +} + + +namespace Botan { + +/** +* Block Cipher Cascade +*/ +class BOTAN_DLL Cascade_Cipher : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return block; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(cipher1->maximum_keylength() + + cipher2->maximum_keylength()); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * Create a cascade of two block ciphers + * @param cipher1 the first cipher + * @param cipher2 the second cipher + */ + Cascade_Cipher(BlockCipher* cipher1, BlockCipher* cipher2); + + ~Cascade_Cipher(); + private: + void key_schedule(const byte[], size_t); + + size_t block; + BlockCipher* cipher1; + BlockCipher* cipher2; + }; + + +} + + +namespace Botan { + +/** +* EME from PKCS #1 v1.5 +*/ +class BOTAN_DLL EME_PKCS1v15 : public EME + { + public: + size_t maximum_input_size(size_t) const; + private: + SecureVector pad(const byte[], size_t, size_t, + RandomNumberGenerator&) const; + SecureVector unpad(const byte[], size_t, size_t) const; + }; + +} + + +namespace Botan { + +/** +* Bit rotation left +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated left by rot bits +*/ +template inline T rotate_left(T input, size_t rot) + { + return static_cast((input << rot) | (input >> (8*sizeof(T)-rot)));; + } + +/** +* Bit rotation right +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated right by rot bits +*/ +template inline T rotate_right(T input, size_t rot) + { + return static_cast((input >> rot) | (input << (8*sizeof(T)-rot))); + } + +} + + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + #include +#endif + +namespace Botan { + +/** +* Swap a 16 bit integer +*/ +inline u16bit reverse_bytes(u16bit val) + { + return rotate_left(val, 8); + } + +/** +* Swap a 32 bit integer +*/ +inline u32bit reverse_bytes(u32bit val) + { +#if BOTAN_GCC_VERSION >= 430 && !defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /* + GCC intrinsic added in 4.3, works for a number of CPUs + + However avoid under ARM, as it branches to a function in libgcc + instead of generating inline asm, so slower even than the generic + rotate version below. + */ + return __builtin_bswap32(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + // GCC-style inline assembly for x86 or x86-64 + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + + asm ("eor r3, %1, %1, ror #16\n\t" + "bic r3, r3, #0x00FF0000\n\t" + "mov %0, %1, ror #8\n\t" + "eor %0, %0, r3, lsr #8" + : "=r" (val) + : "0" (val) + : "r3", "cc"); + + return val; + +#else + + // Generic implementation + return (rotate_right(val, 8) & 0xFF00FF00) | + (rotate_left (val, 8) & 0x00FF00FF); + +#endif + } + +/** +* Swap a 64 bit integer +*/ +inline u64bit reverse_bytes(u64bit val) + { +#if BOTAN_GCC_VERSION >= 430 + + // GCC intrinsic added in 4.3, works for a number of CPUs + return __builtin_bswap64(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_ARCH_IS_X86_64) + // GCC-style inline assembly for x86-64 + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; + +#else + /* Generic implementation. Defined in terms of 32-bit bswap so any + * optimizations in that version can help here (particularly + * useful for 32-bit x86). + */ + + u32bit hi = static_cast(val >> 32); + u32bit lo = static_cast(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast(lo) << 32) | hi; +#endif + } + +/** +* Swap 4 Ts in an array +*/ +template +inline void bswap_4(T x[4]) + { + x[0] = reverse_bytes(x[0]); + x[1] = reverse_bytes(x[1]); + x[2] = reverse_bytes(x[2]); + x[3] = reverse_bytes(x[3]); + } + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + +/** +* Swap 4 u32bits in an array using SSE2 shuffle instructions +*/ +template<> +inline void bswap_4(u32bit x[4]) + { + __m128i T = _mm_loadu_si128(reinterpret_cast(x)); + + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + + T = _mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(x), T); + } + +#endif + +} + + +namespace Botan { + +/** +* MD5 +*/ +class BOTAN_DLL MD5 : public MDx_HashFunction + { + public: + std::string name() const { return "MD5"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new MD5; } + + void clear(); + + MD5() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + protected: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + /** + * The message buffer, exposed for use by subclasses (x86 asm) + */ + SecureVector M; + + /** + * The digest value, exposed for use by subclasses (x86 asm) + */ + SecureVector digest; + }; + +} + + +namespace Botan { + +/** +* Filter mixin that breaks input into blocks, useful for +* cipher modes +*/ +class BOTAN_DLL Buffered_Filter + { + public: + /** + * Write bytes into the buffered filter, which will them emit them + * in calls to buffered_block in the subclass + * @param in the input bytes + * @param length of in in bytes + */ + void write(const byte in[], size_t length); + + /** + * Finish a message, emitting to buffered_block and buffered_final + * Will throw an exception if less than final_minimum bytes were + * written into the filter. + */ + void end_msg(); + + /** + * Initialize a Buffered_Filter + * @param block_size the function buffered_block will be called + * with inputs which are a multiple of this size + * @param final_minimum the function buffered_final will be called + * with at least this many bytes. + */ + Buffered_Filter(size_t block_size, size_t final_minimum); + + virtual ~Buffered_Filter() {} + protected: + /** + * The block processor, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be a multiple + * of block_size + */ + virtual void buffered_block(const byte input[], size_t length) = 0; + + /** + * The final block, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be at least + * final_minimum bytes + */ + virtual void buffered_final(const byte input[], size_t length) = 0; + + /** + * @return block size of inputs + */ + size_t buffered_block_size() const { return main_block_mod; } + + /** + * @return current position in the buffer + */ + size_t current_position() const { return buffer_pos; } + + /** + * Reset the buffer position + */ + void buffer_reset() { buffer_pos = 0; } + private: + size_t main_block_mod, final_minimum; + + SecureVector buffer; + size_t buffer_pos; + }; + +} + + +namespace Botan { + +/** +* ECB Encryption +*/ +class BOTAN_DLL ECB_Encryption : public Keyed_Filter, + private Buffered_Filter + { + public: + std::string name() const; + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad); + + ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key); + + ~ECB_Encryption(); + private: + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + void write(const byte input[], size_t input_length); + void end_msg(); + + BlockCipher* cipher; + BlockCipherModePaddingMethod* padder; + SecureVector temp; + }; + +/** +* ECB Decryption +*/ +class BOTAN_DLL ECB_Decryption : public Keyed_Filter, + public Buffered_Filter + { + public: + std::string name() const; + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad); + + ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key); + + ~ECB_Decryption(); + private: + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + void write(const byte input[], size_t input_length); + void end_msg(); + + BlockCipher* cipher; + BlockCipherModePaddingMethod* padder; + SecureVector temp; + }; + +} + + +namespace Botan { + +/** +* The different charsets (nominally) supported by Botan. +*/ +enum Character_Set { + LOCAL_CHARSET, + UCS2_CHARSET, + UTF8_CHARSET, + LATIN1_CHARSET +}; + +namespace Charset { + +/* +* Character Set Handling +*/ +std::string BOTAN_DLL transcode(const std::string& str, + Character_Set to, + Character_Set from); + +bool BOTAN_DLL is_digit(char c); +bool BOTAN_DLL is_space(char c); +bool BOTAN_DLL caseless_cmp(char x, char y); + +byte BOTAN_DLL char2digit(char c); +char BOTAN_DLL digit2char(byte b); + +} + +} + + +namespace Botan { + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PublicKey : public virtual Public_Key + { + public: + IF_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + IF_Scheme_PublicKey(const BigInt& n, const BigInt& e) : + n(n), e(e) {} + + bool check_key(RandomNumberGenerator& rng, bool) const; + + AlgorithmIdentifier algorithm_identifier() const; + + MemoryVector x509_subject_public_key() const; + + /** + * @return public modulus + */ + const BigInt& get_n() const { return n; } + + /** + * @return public exponent + */ + const BigInt& get_e() const { return e; } + + size_t max_input_bits() const { return (n.bits() - 1); } + + protected: + IF_Scheme_PublicKey() {} + + BigInt n, e; + }; + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PrivateKey : public virtual IF_Scheme_PublicKey, + public virtual Private_Key + { + public: + + IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, const BigInt& prime2, + const BigInt& exp, const BigInt& d_exp, + const BigInt& mod); + + IF_Scheme_PrivateKey(RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the first prime p. + * @return prime p + */ + const BigInt& get_p() const { return p; } + + /** + * Get the second prime q. + * @return prime q + */ + const BigInt& get_q() const { return q; } + + /** + * Get d with exp * d = 1 mod (p - 1, q - 1). + * @return d + */ + const BigInt& get_d() const { return d; } + + const BigInt& get_c() const { return c; } + const BigInt& get_d1() const { return d1; } + const BigInt& get_d2() const { return d2; } + + MemoryVector pkcs8_private_key() const; + + protected: + IF_Scheme_PrivateKey() {} + + BigInt d, p, q, d1, d2, c; + }; + +} + + +namespace Botan { + +/** +* RSA Public Key +*/ +class BOTAN_DLL RSA_PublicKey : public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RSA"; } + + RSA_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + IF_Scheme_PublicKey(alg_id, key_bits) + {} + + /** + * Create a RSA_PublicKey + * @arg n the modulus + * @arg e the exponent + */ + RSA_PublicKey(const BigInt& n, const BigInt& e) : + IF_Scheme_PublicKey(n, e) + {} + + protected: + RSA_PublicKey() {} + }; + +/** +* RSA Private Key +*/ +class BOTAN_DLL RSA_PrivateKey : public RSA_PublicKey, + public IF_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + RSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + IF_Scheme_PrivateKey(rng, alg_id, key_bits) {} + + /** + * Construct a private key from the specified parameters. + * @param rng a random number generator + * @param p the first prime + * @param q the second prime + * @param e the exponent + * @param d if specified, this has to be d with + * exp * d = 1 mod (p - 1, q - 1). Leave it as 0 if you wish to + * the constructor to calculate it. + * @param n if specified, this must be n = p * q. Leave it as 0 + * if you wish to the constructor to calculate it. + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0) : + IF_Scheme_PrivateKey(rng, p, q, e, d, n) {} + + /** + * Create a new private key with the specified bit length + * @param rng the random number generator to use + * @param bits the desired bit length of the private key + * @param exp the public exponent to be used + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp = 65537); + }; + +/** +* RSA private (decrypt/sign) operation +*/ +class BOTAN_DLL RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + RSA_Private_Operation(const RSA_PrivateKey& rsa); + + size_t max_input_bits() const { return (n.bits() - 1); } + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + + SecureVector decrypt(const byte msg[], size_t msg_len); + + private: + BigInt private_op(const BigInt& m) const; + + const BigInt& n; + const BigInt& q; + const BigInt& c; + Fixed_Exponent_Power_Mod powermod_e_n, powermod_d1_p, powermod_d2_q; + Modular_Reducer mod_p; + Blinder blinder; + }; + +/** +* RSA public (encrypt/verify) operation +*/ +class BOTAN_DLL RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), powermod_e_n(rsa.get_e(), rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + SecureVector encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + SecureVector verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + return powermod_e_n(m); + } + + const BigInt& n; + Fixed_Exponent_Power_Mod powermod_e_n; + }; + +} + + +namespace Botan { + +/** +* RIPEMD-160 +*/ +class BOTAN_DLL RIPEMD_160 : public MDx_HashFunction + { + public: + std::string name() const { return "RIPEMD-160"; } + size_t output_length() const { return 20; } + HashFunction* clone() const { return new RIPEMD_160; } + + void clear(); + + RIPEMD_160() : MDx_HashFunction(64, false, true), M(16), digest(5) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector M, digest; + }; + +} + + +namespace Botan { + +/** +* Whirlpool +*/ +class BOTAN_DLL Whirlpool : public MDx_HashFunction + { + public: + std::string name() const { return "Whirlpool"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new Whirlpool; } + + void clear(); + + Whirlpool() : MDx_HashFunction(64, true, true, 32), M(8), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + static const u64bit C0[256]; + static const u64bit C1[256]; + static const u64bit C2[256]; + static const u64bit C3[256]; + static const u64bit C4[256]; + static const u64bit C5[256]; + static const u64bit C6[256]; + static const u64bit C7[256]; + + SecureVector M, digest; + }; + +} + + +namespace Botan { + +/** +* Tiger +*/ +class BOTAN_DLL Tiger : public MDx_HashFunction + { + public: + std::string name() const; + size_t output_length() const { return hash_len; } + + HashFunction* clone() const + { + return new Tiger(output_length(), passes); + } + + void clear(); + + /** + * @param out_size specifies the output length; can be 16, 20, or 24 + * @param passes to make in the algorithm + */ + Tiger(size_t out_size = 24, size_t passes = 3); + private: + void compress_n(const byte[], size_t block); + void copy_out(byte[]); + + static void pass(u64bit& A, u64bit& B, u64bit& C, + const MemoryRegion& M, + byte mul); + + static const u64bit SBOX1[256]; + static const u64bit SBOX2[256]; + static const u64bit SBOX3[256]; + static const u64bit SBOX4[256]; + + SecureVector X, digest; + const size_t hash_len, passes; + }; + +} + + +namespace Botan { + +/** +* SEED, a Korean block cipher +*/ +class BOTAN_DLL SEED : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(K); } + std::string name() const { return "SEED"; } + BlockCipher* clone() const { return new SEED; } + + SEED() : K(32) {} + private: + void key_schedule(const byte[], size_t); + + class G_FUNC + { + public: + u32bit operator()(u32bit) const; + private: + static const u32bit S0[256], S1[256], S2[256], S3[256]; + }; + + SecureVector K; + }; + +} + + +namespace Botan { + +/** +* EMSA3 from IEEE 1363 +* aka PKCS #1 v1.5 signature padding +* aka PKCS #1 block type 1 +*/ +class BOTAN_DLL EMSA3 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA3(HashFunction* hash); + ~EMSA3(); + + void update(const byte[], size_t); + + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + private: + HashFunction* hash; + SecureVector hash_id; + }; + +/** +* EMSA3_Raw which is EMSA3 without a hash or digest id (which +* according to QCA docs is "identical to PKCS#11's CKM_RSA_PKCS +* mechanism", something I have not confirmed) +*/ +class BOTAN_DLL EMSA3_Raw : public EMSA + { + public: + void update(const byte[], size_t); + + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + + private: + SecureVector message; + }; + +} + + +namespace Botan { + +/** +* Twofish, an AES finalist +*/ +class BOTAN_DLL Twofish : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Twofish"; } + BlockCipher* clone() const { return new Twofish; } + + Twofish() : SB(1024), RK(40) {} + private: + void key_schedule(const byte[], size_t); + + static void rs_mul(byte[4], byte, size_t); + + static const u32bit MDS0[256]; + static const u32bit MDS1[256]; + static const u32bit MDS2[256]; + static const u32bit MDS3[256]; + static const byte Q0[256]; + static const byte Q1[256]; + static const byte RS[32]; + static const byte EXP_TO_POLY[255]; + static const byte POLY_TO_EXP[255]; + + SecureVector SB, RK; + }; + +} + + +namespace Botan { + +/** +* Create a password hash using PBKDF2 +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* @param alg_id specifies which PRF to use with PBKDF2 +* 0 is HMAC(SHA-1) +* 1 is HMAC(SHA-256) +* 2 is CMAC(Blowfish) +* all other values are currently undefined +*/ +std::string BOTAN_DLL generate_passhash9(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10, + byte alg_id = 0); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_passhash9(const std::string& password, + const std::string& hash); + +} + + +namespace Botan { + +/** +* SHA-224 +*/ +class BOTAN_DLL SHA_224 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-224"; } + size_t output_length() const { return 28; } + HashFunction* clone() const { return new SHA_224; } + + void clear(); + + SHA_224() : MDx_HashFunction(64, true, true), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector digest; + }; + +/** +* SHA-256 +*/ +class BOTAN_DLL SHA_256 : public MDx_HashFunction + { + public: + std::string name() const { return "SHA-256"; } + size_t output_length() const { return 32; } + HashFunction* clone() const { return new SHA_256; } + + void clear(); + + SHA_256() : MDx_HashFunction(64, true, true), digest(8) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector digest; + }; + +} + + +namespace Botan { + +/** +* Blue Midnight Wish 512 (Round 2 tweaked version) +*/ +class BOTAN_DLL BMW_512 : public MDx_HashFunction + { + public: + std::string name() const { return "BMW512"; } + size_t output_length() const { return 64; } + HashFunction* clone() const { return new BMW_512; } + + void clear(); + + BMW_512() : MDx_HashFunction(128, false, true), H(16), M(16), Q(32) + { clear(); } + private: + void compress_n(const byte input[], size_t blocks); + void copy_out(byte output[]); + + SecureVector H, M, Q; + }; + +} + + +namespace Botan { + +/** +* @param input the input data +* @param length length of input in bytes +* @param label the human-readable label +* @param headers a set of key/value pairs included in the header +*/ +BOTAN_DLL std::string PGP_encode( + const byte input[], + size_t length, + const std::string& label, + const std::map& headers); + +/** +* @param input the input data +* @param length length of input in bytes +* @param label the human-readable label +*/ +BOTAN_DLL std::string PGP_encode( + const byte input[], + size_t length, + const std::string& label); + +/** +* @param source the input source +* @param label is set to the human-readable label +* @param headers is set to any headers +* @return decoded output as raw binary +*/ +BOTAN_DLL SecureVector PGP_decode( + DataSource& source, + std::string& label, + std::map& headers); + +/** +* @param source the input source +* @param label is set to the human-readable label +* @return decoded output as raw binary +*/ +BOTAN_DLL SecureVector PGP_decode( + DataSource& source, + std::string& label); + +} + + +namespace Botan { + +/** +* Certificate Store Interface +*/ +class BOTAN_DLL Certificate_Store + { + public: + virtual ~Certificate_Store() {} + + virtual Certificate_Store* clone() const = 0; + + /** + * Add a certificate; this may fail if the store is write-only + */ + virtual void add_certificate(const X509_Certificate& cert) = 0; + + /** + * Add a CRL; this may fail if the store is write-only + */ + virtual void add_crl(const X509_CRL& crl) = 0; + + /** + * Subject DN and (optionally) key identifier + */ + virtual std::vector + find_cert_by_subject_and_key_id( + const X509_DN& subject_dn, + const MemoryRegion& key_id) const = 0; + + /** + * Find CRLs by the DN and key id of the issuer + */ + virtual std::vector + find_crl_by_subject_and_key_id( + const X509_DN& issuer_dn, + const MemoryRegion& key_id) const = 0; + }; + +/** +* In Memory Certificate Store +*/ +class BOTAN_DLL Certificate_Store_Memory : public Certificate_Store + { + public: + Certificate_Store* clone() const; + + void add_certificate(const X509_Certificate& cert); + + void add_crl(const X509_CRL& crl); + + std::vector find_cert_by_subject_and_key_id( + const X509_DN& subject_dn, + const MemoryRegion& key_id) const; + + std::vector find_crl_by_subject_and_key_id( + const X509_DN& issuer_dn, + const MemoryRegion& key_id) const; + + Certificate_Store_Memory() {} + private: + // TODO: Add indexing on the DN and key id to avoid linear search? + std::vector certs; + std::vector crls; + }; + +// TODO: file-backed store + +} + + +namespace Botan { + +/** +* KDF2, from IEEE 1363 +*/ +class BOTAN_DLL KDF2 : public KDF + { + public: + SecureVector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "KDF2(" + hash->name() + ")"; } + KDF* clone() const { return new KDF2(hash->clone()); } + + KDF2(HashFunction* h) : hash(h) {} + KDF2(const KDF2& other) : KDF(), hash(other.hash->clone()) {} + ~KDF2() { delete hash; } + private: + HashFunction* hash; + }; + +} + + +namespace Botan { + +namespace KeyPair { + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_DLL bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding); + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_DLL bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding); + +} + +} + + +namespace Botan { + +/** +* This namespace holds various high-level crypto functions +*/ +namespace CryptoBox { + +/** +* Encrypt a message using a passphrase +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +* @param rng a ref to a random number generator, such as AutoSeeded_RNG +*/ +BOTAN_DLL std::string encrypt(const byte input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_DLL std::string decrypt(const byte input[], size_t input_len, + const std::string& passphrase); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_DLL std::string decrypt(const std::string& input, + const std::string& passphrase); + +} + +} + + +namespace Botan { + +/** +* X.509 Certificate Validation Result +*/ +enum X509_Code { + VERIFIED, + UNKNOWN_X509_ERROR, + CANNOT_ESTABLISH_TRUST, + CERT_CHAIN_TOO_LONG, + SIGNATURE_ERROR, + POLICY_ERROR, + INVALID_USAGE, + + CERT_FORMAT_ERROR, + CERT_ISSUER_NOT_FOUND, + CERT_NOT_YET_VALID, + CERT_HAS_EXPIRED, + CERT_IS_REVOKED, + + CRL_FORMAT_ERROR, + CRL_ISSUER_NOT_FOUND, + CRL_NOT_YET_VALID, + CRL_HAS_EXPIRED, + + CA_CERT_CANNOT_SIGN, + CA_CERT_NOT_FOR_CERT_ISSUER, + CA_CERT_NOT_FOR_CRL_ISSUER +}; + +/** +* X.509 Certificate Store +*/ +class BOTAN_DLL X509_Store + { + public: + enum Cert_Usage { + ANY = 0x00, + TLS_SERVER = 0x01, + TLS_CLIENT = 0x02, + CODE_SIGNING = 0x04, + EMAIL_PROTECTION = 0x08, + TIME_STAMPING = 0x10, + CRL_SIGNING = 0x20 + }; + + X509_Code validate_cert(const X509_Certificate&, Cert_Usage = ANY); + + std::vector get_cert_chain(const X509_Certificate&); + std::string PEM_encode() const; + + X509_Code add_crl(const X509_CRL&); + void add_cert(const X509_Certificate&, bool = false); + void add_certs(DataSource&); + void add_trusted_certs(DataSource&); + + void add_new_certstore(Certificate_Store*); + + X509_Store(u32bit time_slack = 24*60*60, + u32bit cache_results = 30*60); + + X509_Store(const X509_Store&); + ~X509_Store(); + private: + X509_Store& operator=(const X509_Store&) { return (*this); } + + class BOTAN_DLL CRL_Data + { + public: + X509_DN issuer; + MemoryVector serial, auth_key_id; + bool operator==(const CRL_Data&) const; + bool operator!=(const CRL_Data&) const; + bool operator<(const CRL_Data&) const; + }; + + class BOTAN_DLL Cert_Info + { + public: + bool is_verified(u32bit timeout) const; + bool is_trusted() const; + X509_Code verify_result() const; + void set_result(X509_Code) const; + Cert_Info(const X509_Certificate&, bool = false); + + X509_Certificate cert; + bool trusted; + private: + mutable bool checked; + mutable X509_Code result; + mutable u64bit last_checked; + }; + + static X509_Code check_sig(const X509_Object&, Public_Key*); + + size_t find_cert(const X509_DN&, const MemoryRegion&) const; + X509_Code check_sig(const Cert_Info&, const Cert_Info&) const; + void recompute_revoked_info() const; + + void do_add_certs(DataSource&, bool); + X509_Code construct_cert_chain(const X509_Certificate&, + std::vector&, bool = false); + + size_t find_parent_of(const X509_Certificate&); + bool is_revoked(const X509_Certificate&) const; + + static const size_t NO_CERT_FOUND = 0xFFFFFFFF; + std::vector certs; + std::vector revoked; + std::vector stores; + u32bit time_slack, validation_cache_timeout; + mutable bool revoked_info_valid; + }; + +} + + +namespace Botan { + +/** +* Noekeon +*/ +class BOTAN_DLL Noekeon : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Noekeon"; } + BlockCipher* clone() const { return new Noekeon; } + + Noekeon() : EK(4), DK(4) {} + protected: + /** + * The Noekeon round constants + */ + static const byte RC[17]; + + /** + * @return const reference to encryption subkeys + */ + const SecureVector& get_EK() const { return EK; } + + /** + * @return const reference to decryption subkeys + */ + const SecureVector& get_DK() const { return DK; } + + private: + void key_schedule(const byte[], size_t); + SecureVector EK, DK; + }; + +} + + +namespace Botan { + +/** +* Create a password hash using Bcrypt +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* +* @see http://www.usenix.org/events/usenix99/provos/provos_html/ +*/ +std::string BOTAN_DLL generate_bcrypt(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_bcrypt(const std::string& password, + const std::string& hash); + +} + + +namespace Botan { + +/** +* CFB Encryption +*/ +class BOTAN_DLL CFB_Encryption : public Keyed_Filter + { + public: + std::string name() const { return cipher->name() + "/CFB"; } + + void set_iv(const InitializationVector&); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CFB_Encryption(BlockCipher* cipher, size_t feedback = 0); + + CFB_Encryption(BlockCipher* cipher, + const SymmetricKey& key, + const InitializationVector& iv, + size_t feedback = 0); + + ~CFB_Encryption() { delete cipher; } + private: + void write(const byte[], size_t); + + BlockCipher* cipher; + SecureVector buffer, state; + size_t position, feedback; + }; + +/** +* CFB Decryption +*/ +class BOTAN_DLL CFB_Decryption : public Keyed_Filter + { + public: + std::string name() const { return cipher->name() + "/CFB"; } + + void set_iv(const InitializationVector&); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CFB_Decryption(BlockCipher* cipher, size_t feedback = 0); + + CFB_Decryption(BlockCipher* cipher, + const SymmetricKey& key, + const InitializationVector& iv, + size_t feedback = 0); + + ~CFB_Decryption() { delete cipher; } + private: + void write(const byte[], size_t); + + BlockCipher* cipher; + SecureVector buffer, state; + size_t position, feedback; + }; + +} + + +namespace Botan { + +/** +* X.509 Certificate Extension +*/ +class BOTAN_DLL Certificate_Extension + { + public: + /** + * @return OID representing this extension + */ + OID oid_of() const; + + /** + * Make a copy of this extension + * @return copy of this + */ + virtual Certificate_Extension* copy() const = 0; + + /* + * Add the contents of this extension into the information + * for the subject and/or issuer, as necessary. + * @param subject the subject info + * @param issuer the issuer info + */ + virtual void contents_to(Data_Store& subject, + Data_Store& issuer) const = 0; + + /* + * @return short readable name + */ + virtual std::string config_id() const = 0; + + /* + * @return specific OID name + */ + virtual std::string oid_name() const = 0; + + virtual ~Certificate_Extension() {} + protected: + friend class Extensions; + virtual bool should_encode() const { return true; } + virtual MemoryVector encode_inner() const = 0; + virtual void decode_inner(const MemoryRegion&) = 0; + }; + +/** +* X.509 Certificate Extension List +*/ +class BOTAN_DLL Extensions : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const; + void decode_from(class BER_Decoder&); + + void contents_to(Data_Store&, Data_Store&) const; + + void add(Certificate_Extension* extn, bool critical = false); + + Extensions& operator=(const Extensions&); + + Extensions(const Extensions&); + Extensions(bool st = true) : should_throw(st) {} + ~Extensions(); + private: + static Certificate_Extension* get_extension(const OID&); + + std::vector > extensions; + bool should_throw; + }; + +namespace Cert_Extension { + +static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0; + +/** +* Basic Constraints Extension +*/ +class BOTAN_DLL Basic_Constraints : public Certificate_Extension + { + public: + Basic_Constraints* copy() const + { return new Basic_Constraints(is_ca, path_limit); } + + Basic_Constraints(bool ca = false, size_t limit = 0) : + is_ca(ca), path_limit(limit) {} + + bool get_is_ca() const { return is_ca; } + size_t get_path_limit() const; + private: + std::string config_id() const { return "basic_constraints"; } + std::string oid_name() const { return "X509v3.BasicConstraints"; } + + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + bool is_ca; + size_t path_limit; + }; + +/** +* Key Usage Constraints Extension +*/ +class BOTAN_DLL Key_Usage : public Certificate_Extension + { + public: + Key_Usage* copy() const { return new Key_Usage(constraints); } + + Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : constraints(c) {} + + Key_Constraints get_constraints() const { return constraints; } + private: + std::string config_id() const { return "key_usage"; } + std::string oid_name() const { return "X509v3.KeyUsage"; } + + bool should_encode() const { return (constraints != NO_CONSTRAINTS); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + Key_Constraints constraints; + }; + +/** +* Subject Key Identifier Extension +*/ +class BOTAN_DLL Subject_Key_ID : public Certificate_Extension + { + public: + Subject_Key_ID* copy() const { return new Subject_Key_ID(key_id); } + + Subject_Key_ID() {} + Subject_Key_ID(const MemoryRegion&); + + MemoryVector get_key_id() const { return key_id; } + private: + std::string config_id() const { return "subject_key_id"; } + std::string oid_name() const { return "X509v3.SubjectKeyIdentifier"; } + + bool should_encode() const { return (key_id.size() > 0); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + MemoryVector key_id; + }; + +/** +* Authority Key Identifier Extension +*/ +class BOTAN_DLL Authority_Key_ID : public Certificate_Extension + { + public: + Authority_Key_ID* copy() const { return new Authority_Key_ID(key_id); } + + Authority_Key_ID() {} + Authority_Key_ID(const MemoryRegion& k) : key_id(k) {} + + MemoryVector get_key_id() const { return key_id; } + private: + std::string config_id() const { return "authority_key_id"; } + std::string oid_name() const { return "X509v3.AuthorityKeyIdentifier"; } + + bool should_encode() const { return (key_id.size() > 0); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + MemoryVector key_id; + }; + +/** +* Alternative Name Extension Base Class +*/ +class BOTAN_DLL Alternative_Name : public Certificate_Extension + { + public: + AlternativeName get_alt_name() const { return alt_name; } + + protected: + Alternative_Name(const AlternativeName&, + const std::string&, const std::string&); + + Alternative_Name(const std::string&, const std::string&); + private: + std::string config_id() const { return config_name_str; } + std::string oid_name() const { return oid_name_str; } + + bool should_encode() const { return alt_name.has_items(); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + std::string config_name_str, oid_name_str; + AlternativeName alt_name; + }; + +/** +* Subject Alternative Name Extension +*/ +class BOTAN_DLL Subject_Alternative_Name : public Alternative_Name + { + public: + Subject_Alternative_Name* copy() const + { return new Subject_Alternative_Name(get_alt_name()); } + + Subject_Alternative_Name(const AlternativeName& = AlternativeName()); + }; + +/** +* Issuer Alternative Name Extension +*/ +class BOTAN_DLL Issuer_Alternative_Name : public Alternative_Name + { + public: + Issuer_Alternative_Name* copy() const + { return new Issuer_Alternative_Name(get_alt_name()); } + + Issuer_Alternative_Name(const AlternativeName& = AlternativeName()); + }; + +/** +* Extended Key Usage Extension +*/ +class BOTAN_DLL Extended_Key_Usage : public Certificate_Extension + { + public: + Extended_Key_Usage* copy() const { return new Extended_Key_Usage(oids); } + + Extended_Key_Usage() {} + Extended_Key_Usage(const std::vector& o) : oids(o) {} + + std::vector get_oids() const { return oids; } + private: + std::string config_id() const { return "extended_key_usage"; } + std::string oid_name() const { return "X509v3.ExtendedKeyUsage"; } + + bool should_encode() const { return (oids.size() > 0); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector oids; + }; + +/** +* Certificate Policies Extension +*/ +class BOTAN_DLL Certificate_Policies : public Certificate_Extension + { + public: + Certificate_Policies* copy() const + { return new Certificate_Policies(oids); } + + Certificate_Policies() {} + Certificate_Policies(const std::vector& o) : oids(o) {} + + std::vector get_oids() const { return oids; } + private: + std::string config_id() const { return "policy_info"; } + std::string oid_name() const { return "X509v3.CertificatePolicies"; } + + bool should_encode() const { return (oids.size() > 0); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + std::vector oids; + }; + +/** +* CRL Number Extension +*/ +class BOTAN_DLL CRL_Number : public Certificate_Extension + { + public: + CRL_Number* copy() const; + + CRL_Number() : has_value(false), crl_number(0) {} + CRL_Number(size_t n) : has_value(true), crl_number(n) {} + + size_t get_crl_number() const; + private: + std::string config_id() const { return "crl_number"; } + std::string oid_name() const { return "X509v3.CRLNumber"; } + + bool should_encode() const { return has_value; } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + bool has_value; + size_t crl_number; + }; + +/** +* CRL Entry Reason Code Extension +*/ +class BOTAN_DLL CRL_ReasonCode : public Certificate_Extension + { + public: + CRL_ReasonCode* copy() const { return new CRL_ReasonCode(reason); } + + CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : reason(r) {} + + CRL_Code get_reason() const { return reason; } + private: + std::string config_id() const { return "crl_reason"; } + std::string oid_name() const { return "X509v3.ReasonCode"; } + + bool should_encode() const { return (reason != UNSPECIFIED); } + MemoryVector encode_inner() const; + void decode_inner(const MemoryRegion&); + void contents_to(Data_Store&, Data_Store&) const; + + CRL_Code reason; + }; + +} + +} + + +namespace Botan { + +/** +* DSA Public Key +*/ +class BOTAN_DLL DSA_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DSA"; } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + size_t message_parts() const { return 2; } + size_t message_part_size() const { return group_q().bytes(); } + size_t max_input_bits() const { return group_q().bits(); } + + DSA_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + + DSA_PublicKey(const DL_Group& group, const BigInt& y); + protected: + DSA_PublicKey() {} + }; + +/** +* DSA Private Key +*/ +class BOTAN_DLL DSA_PrivateKey : public DSA_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng); + + DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& private_key = 0); + + bool check_key(RandomNumberGenerator& rng, bool strong) const; + }; + +/** +* Object that can create a DSA signature +*/ +class BOTAN_DLL DSA_Signature_Operation : public PK_Ops::Signature + { + public: + DSA_Signature_Operation(const DSA_PrivateKey& dsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return q.bits(); } + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& q; + const BigInt& x; + Fixed_Base_Power_Mod powermod_g_p; + Modular_Reducer mod_q; + }; + +/** +* Object that can verify a DSA signature +*/ +class BOTAN_DLL DSA_Verification_Operation : public PK_Ops::Verification + { + public: + DSA_Verification_Operation(const DSA_PublicKey& dsa); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return q.bits(); } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const BigInt& q; + const BigInt& y; + + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + +} + + +namespace Botan { + +/** +* PRF from ANSI X9.42 +*/ +class BOTAN_DLL X942_PRF : public KDF + { + public: + SecureVector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "X942_PRF(" + key_wrap_oid + ")"; } + KDF* clone() const { return new X942_PRF(key_wrap_oid); } + + X942_PRF(const std::string& oid); + private: + std::string key_wrap_oid; + }; + +} + + +namespace Botan { + +/** +* TEA +*/ +class BOTAN_DLL TEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(K); } + std::string name() const { return "TEA"; } + BlockCipher* clone() const { return new TEA; } + + TEA() : K(4) {} + private: + void key_schedule(const byte[], size_t); + SecureVector K; + }; + +} + + +namespace Botan { + +/** +* Nyberg-Rueppel Public Key +*/ +class BOTAN_DLL NR_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "NR"; } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return group_q().bytes(); } + size_t max_input_bits() const { return (group_q().bits() - 1); } + + NR_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits); + + NR_PublicKey(const DL_Group& group, const BigInt& pub_key); + protected: + NR_PublicKey() {} + }; + +/** +* Nyberg-Rueppel Private Key +*/ +class BOTAN_DLL NR_PrivateKey : public NR_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool strong) const; + + NR_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng); + + NR_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& x = 0); + }; + +/** +* Nyberg-Rueppel signature operation +*/ +class BOTAN_DLL NR_Signature_Operation : public PK_Ops::Signature + { + public: + NR_Signature_Operation(const NR_PrivateKey& nr); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return (q.bits() - 1); } + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& q; + const BigInt& x; + Fixed_Base_Power_Mod powermod_g_p; + Modular_Reducer mod_q; + }; + +/** +* Nyberg-Rueppel verification operation +*/ +class BOTAN_DLL NR_Verification_Operation : public PK_Ops::Verification + { + public: + NR_Verification_Operation(const NR_PublicKey& nr); + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return q.bytes(); } + size_t max_input_bits() const { return (q.bits() - 1); } + + bool with_recovery() const { return true; } + + SecureVector verify_mr(const byte msg[], size_t msg_len); + private: + const BigInt& q; + const BigInt& y; + + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + +} + + +namespace Botan { + +/** +* Alleged RC4 +*/ +class BOTAN_DLL ARC4 : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void clear(); + std::string name() const; + + StreamCipher* clone() const { return new ARC4(SKIP); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 256); + } + + /** + * @param skip skip this many initial bytes in the keystream + */ + ARC4(size_t skip = 0); + + ~ARC4() { clear(); } + private: + void key_schedule(const byte[], size_t); + void generate(); + + const size_t SKIP; + + byte X, Y; + SecureVector state; + + SecureVector buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* Rabin-Williams Public Key +*/ +class BOTAN_DLL RW_PublicKey : public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RW"; } + + RW_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + IF_Scheme_PublicKey(alg_id, key_bits) + {} + + RW_PublicKey(const BigInt& mod, const BigInt& exponent) : + IF_Scheme_PublicKey(mod, exponent) + {} + + protected: + RW_PublicKey() {} + }; + +/** +* Rabin-Williams Private Key +*/ +class BOTAN_DLL RW_PrivateKey : public RW_PublicKey, + public IF_Scheme_PrivateKey + { + public: + RW_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits, + RandomNumberGenerator& rng) : + IF_Scheme_PrivateKey(rng, alg_id, key_bits) {} + + RW_PrivateKey(RandomNumberGenerator& rng, + const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0) : + IF_Scheme_PrivateKey(rng, p, q, e, d, n) {} + + RW_PrivateKey(RandomNumberGenerator& rng, size_t bits, size_t = 2); + + bool check_key(RandomNumberGenerator& rng, bool) const; + }; + +/** +* Rabin-Williams Signature Operation +*/ +class BOTAN_DLL RW_Signature_Operation : public PK_Ops::Signature + { + public: + RW_Signature_Operation(const RW_PrivateKey& rw); + + size_t max_input_bits() const { return (n.bits() - 1); } + + SecureVector sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const BigInt& n; + const BigInt& e; + const BigInt& q; + const BigInt& c; + + Fixed_Exponent_Power_Mod powermod_d1_p, powermod_d2_q; + Modular_Reducer mod_p; + Blinder blinder; + }; + +/** +* Rabin-Williams Verification Operation +*/ +class BOTAN_DLL RW_Verification_Operation : public PK_Ops::Verification + { + public: + RW_Verification_Operation(const RW_PublicKey& rw) : + n(rw.get_n()), powermod_e_n(rw.get_e(), rw.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + SecureVector verify_mr(const byte msg[], size_t msg_len); + + private: + const BigInt& n; + Fixed_Exponent_Power_Mod powermod_e_n; + }; + +} + + +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + +#define BOTAN_ENDIAN_N2B(x) (x) +#define BOTAN_ENDIAN_B2N(x) (x) + +#define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) +#define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + +#define BOTAN_ENDIAN_N2L(x) (x) +#define BOTAN_ENDIAN_L2N(x) (x) + +#define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) +#define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) + +#endif + +#endif + +namespace Botan { + +/** +* Make a u16bit from two bytes +* @param i0 the first byte +* @param i1 the second byte +* @return i0 || i1 +*/ +inline u16bit make_u16bit(byte i0, byte i1) + { + return ((static_cast(i0) << 8) | i1); + } + +/** +* Make a u32bit from four bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @return i0 || i1 || i2 || i3 +*/ +inline u32bit make_u32bit(byte i0, byte i1, byte i2, byte i3) + { + return ((static_cast(i0) << 24) | + (static_cast(i1) << 16) | + (static_cast(i2) << 8) | + (static_cast(i3))); + } + +/** +* Make a u32bit from eight bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @param i4 the fifth byte +* @param i5 the sixth byte +* @param i6 the seventh byte +* @param i7 the eighth byte +* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 +*/ +inline u64bit make_u64bit(byte i0, byte i1, byte i2, byte i3, + byte i4, byte i5, byte i6, byte i7) + { + return ((static_cast(i0) << 56) | + (static_cast(i1) << 48) | + (static_cast(i2) << 40) | + (static_cast(i3) << 32) | + (static_cast(i4) << 24) | + (static_cast(i5) << 16) | + (static_cast(i6) << 8) | + (static_cast(i7))); + } + +/** +* Load a big-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a big-endian value +*/ +template +inline T load_be(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[i]; + return out; + } + +/** +* Load a little-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a litte-endian value +*/ +template +inline T load_le(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[sizeof(T)-1-i]; + return out; + } + +/** +* Load a big-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a big-endian value +*/ +template<> +inline u16bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[0], in[1]); +#endif + } + +/** +* Load a little-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a little-endian value +*/ +template<> +inline u16bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[1], in[0]); +#endif + } + +/** +* Load a big-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a big-endian value +*/ +template<> +inline u32bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[0], in[1], in[2], in[3]); +#endif + } + +/** +* Load a little-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a little-endian value +*/ +template<> +inline u32bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load a big-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a big-endian value +*/ +template<> +inline u64bit load_be(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7]); +#endif + } + +/** +* Load a little-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a little-endian value +*/ +template<> +inline u64bit load_le(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[7], in[6], in[5], in[4], + in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load two little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_le(const byte in[], T& x0, T& x1) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + } + +/** +* Load four little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + } + +/** +* Load eight little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + x4 = load_le(in, 4); + x5 = load_le(in, 5); + x6 = load_le(in, 6); + x7 = load_le(in, 7); + } + +/** +* Load a variable number of little-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_le(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_le(in, i); +#endif + } + +/** +* Load two big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_be(const byte in[], T& x0, T& x1) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + } + +/** +* Load four big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + } + +/** +* Load eight big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + x4 = load_be(in, 4); + x5 = load_be(in, 5); + x6 = load_be(in, 6); + x7 = load_be(in, 7); + } + +/** +* Load a variable number of big-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_be(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_be(in, i); +#endif + } + +/** +* Store a big-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_be(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); +#endif + } + +/** +* Store a little-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_le(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(1, in); + out[1] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_be(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); +#endif + } + +/** +* Store a little-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_le(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(3, in); + out[1] = get_byte(2, in); + out[2] = get_byte(1, in); + out[3] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_be(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); + out[4] = get_byte(4, in); + out[5] = get_byte(5, in); + out[6] = get_byte(6, in); + out[7] = get_byte(7, in); +#endif + } + +/** +* Store a little-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_le(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(7, in); + out[1] = get_byte(6, in); + out[2] = get_byte(5, in); + out[3] = get_byte(4, in); + out[4] = get_byte(3, in); + out[5] = get_byte(2, in); + out[6] = get_byte(1, in); + out[7] = get_byte(0, in); +#endif + } + +/** +* Store two little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_le(byte out[], T x0, T x1) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + } + +/** +* Store two big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_be(byte out[], T x0, T x1) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + } + +/** +* Store four little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_le(byte out[], T x0, T x1, T x2, T x3) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + } + +/** +* Store four big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_be(byte out[], T x0, T x1, T x2, T x3) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + } + +/** +* Store eight little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_le(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + store_le(x4, out + (4 * sizeof(T))); + store_le(x5, out + (5 * sizeof(T))); + store_le(x6, out + (6 * sizeof(T))); + store_le(x7, out + (7 * sizeof(T))); + } + +/** +* Store eight big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_be(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + store_be(x4, out + (4 * sizeof(T))); + store_be(x5, out + (5 * sizeof(T))); + store_be(x6, out + (6 * sizeof(T))); + store_be(x7, out + (7 * sizeof(T))); + } + +} + + +namespace Botan { + +/** +* CBC Encryption +*/ +class BOTAN_DLL CBC_Encryption : public Keyed_Filter, + private Buffered_Filter + { + public: + std::string name() const; + + void set_iv(const InitializationVector& iv); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CBC_Encryption(BlockCipher* cipher, + BlockCipherModePaddingMethod* padding); + + CBC_Encryption(BlockCipher* cipher, + BlockCipherModePaddingMethod* padding, + const SymmetricKey& key, + const InitializationVector& iv); + + ~CBC_Encryption() { delete cipher; delete padder; } + private: + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + void write(const byte input[], size_t input_length); + void end_msg(); + + BlockCipher* cipher; + const BlockCipherModePaddingMethod* padder; + SecureVector state; + }; + +/** +* CBC Decryption +*/ +class BOTAN_DLL CBC_Decryption : public Keyed_Filter, + private Buffered_Filter + { + public: + std::string name() const; + + void set_iv(const InitializationVector& iv); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CBC_Decryption(BlockCipher* cipher, + BlockCipherModePaddingMethod* padding); + + CBC_Decryption(BlockCipher* cipher, + BlockCipherModePaddingMethod* padding, + const SymmetricKey& key, + const InitializationVector& iv); + + ~CBC_Decryption() { delete cipher; delete padder; } + private: + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + void write(const byte[], size_t); + void end_msg(); + + BlockCipher* cipher; + const BlockCipherModePaddingMethod* padder; + SecureVector state, temp; + }; + +} + + +namespace Botan { + +/** +* A class handling runtime CPU feature detection +*/ +class BOTAN_DLL CPUID + { + public: + /** + * Probe the CPU and see what extensions are supported + */ + static void initialize(); + + /** + * Return a best guess of the cache line size + */ + static size_t cache_line_size() { return cache_line; } + + /** + * Check if the processor supports RDTSC + */ + static bool has_rdtsc() + { return x86_processor_flags_has(CPUID_RDTSC_BIT); } + + /** + * Check if the processor supports SSE2 + */ + static bool has_sse2() + { return x86_processor_flags_has(CPUID_SSE2_BIT); } + + /** + * Check if the processor supports SSSE3 + */ + static bool has_ssse3() + { return x86_processor_flags_has(CPUID_SSSE3_BIT); } + + /** + * Check if the processor supports SSE4.1 + */ + static bool has_sse41() + { return x86_processor_flags_has(CPUID_SSE41_BIT); } + + /** + * Check if the processor supports SSE4.2 + */ + static bool has_sse42() + { return x86_processor_flags_has(CPUID_SSE42_BIT); } + + /** + * Check if the processor supports extended AVX vector instructions + */ + static bool has_avx() + { return x86_processor_flags_has(CPUID_AVX_BIT); } + + /** + * Check if the processor supports AES-NI + */ + static bool has_aes_ni() + { return x86_processor_flags_has(CPUID_AESNI_BIT); } + + /** + * Check if the processor supports PCMULUDQ + */ + static bool has_pcmuludq() + { return x86_processor_flags_has(CPUID_PCMUL_BIT); } + + /** + * Check if the processor supports MOVBE + */ + static bool has_movbe() + { return x86_processor_flags_has(CPUID_MOVBE_BIT); } + + /** + * Check if the processor supports RDRAND + */ + static bool has_rdrand() + { return x86_processor_flags_has(CPUID_RDRAND_BIT); } + + /** + * Check if the processor supports AltiVec/VMX + */ + static bool has_altivec() { return altivec_capable; } + private: + enum CPUID_bits { + CPUID_RDTSC_BIT = 4, + CPUID_SSE2_BIT = 26, + CPUID_PCMUL_BIT = 33, + CPUID_SSSE3_BIT = 41, + CPUID_SSE41_BIT = 51, + CPUID_SSE42_BIT = 52, + CPUID_MOVBE_BIT = 54, + CPUID_AESNI_BIT = 57, + CPUID_AVX_BIT = 60, + CPUID_RDRAND_BIT = 62 + }; + + static bool x86_processor_flags_has(u64bit bit) + { + return ((x86_processor_flags >> bit) & 1); + } + + static u64bit x86_processor_flags; + static size_t cache_line; + static bool altivec_capable; + }; + +} + + +namespace Botan { + +/** +* Serpent implementation using SIMD +*/ +class BOTAN_DLL Serpent_SIMD : public Serpent + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new Serpent_SIMD; } + }; + +} + + +namespace Botan { + +/** +* PK_Encryptor Filter +*/ +class BOTAN_DLL PK_Encryptor_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + PK_Encryptor_Filter(PK_Encryptor* c, + RandomNumberGenerator& rng_ref) : + cipher(c), rng(rng_ref) {} + ~PK_Encryptor_Filter() { delete cipher; } + private: + PK_Encryptor* cipher; + RandomNumberGenerator& rng; + SecureVector buffer; + }; + +/** +* PK_Decryptor Filter +*/ +class BOTAN_DLL PK_Decryptor_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + PK_Decryptor_Filter(PK_Decryptor* c) : cipher(c) {} + ~PK_Decryptor_Filter() { delete cipher; } + private: + PK_Decryptor* cipher; + SecureVector buffer; + }; + +/** +* PK_Signer Filter +*/ +class BOTAN_DLL PK_Signer_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + + PK_Signer_Filter(PK_Signer* s, + RandomNumberGenerator& rng_ref) : + signer(s), rng(rng_ref) {} + + ~PK_Signer_Filter() { delete signer; } + private: + PK_Signer* signer; + RandomNumberGenerator& rng; + }; + +/** +* PK_Verifier Filter +*/ +class BOTAN_DLL PK_Verifier_Filter : public Filter + { + public: + void write(const byte[], size_t); + void end_msg(); + + void set_signature(const byte[], size_t); + void set_signature(const MemoryRegion&); + + PK_Verifier_Filter(PK_Verifier* v) : verifier(v) {} + PK_Verifier_Filter(PK_Verifier*, const byte[], size_t); + PK_Verifier_Filter(PK_Verifier*, const MemoryRegion&); + ~PK_Verifier_Filter() { delete verifier; } + private: + PK_Verifier* verifier; + SecureVector signature; + }; + +} + + +namespace Botan { + +/** +* XTEA implemented using SIMD operations +*/ +class BOTAN_DLL XTEA_SIMD : public XTEA + { + public: + size_t parallelism() const { return 8; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + BlockCipher* clone() const { return new XTEA_SIMD; } + }; + +} + + +namespace Botan { + +/** +* A queue that knows how to zeroize itself +*/ +class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource + { + public: + std::string name() const { return "Queue"; } + + void write(const byte[], size_t); + + size_t read(byte[], size_t); + size_t peek(byte[], size_t, size_t = 0) const; + + bool end_of_data() const; + + /** + * @return number of bytes available in the queue + */ + size_t size() const; + + bool attachable() { return false; } + + /** + * SecureQueue assignment + * @param other the queue to copy + */ + SecureQueue& operator=(const SecureQueue& other); + + /** + * SecureQueue default constructor (creates empty queue) + */ + SecureQueue(); + + /** + * SecureQueue copy constructor + * @param other the queue to copy + */ + SecureQueue(const SecureQueue& other); + + ~SecureQueue() { destroy(); } + private: + void destroy(); + class SecureQueueNode* head; + class SecureQueueNode* tail; + }; + +} + + +namespace Botan { + +/** +* HMAC +*/ +class BOTAN_DLL HMAC : public MessageAuthenticationCode + { + public: + void clear(); + std::string name() const; + MessageAuthenticationCode* clone() const; + + size_t output_length() const { return hash->output_length(); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(0, 2*hash->hash_block_size()); + } + + /** + * @param hash the hash to use for HMACing + */ + HMAC(HashFunction* hash); + ~HMAC() { delete hash; } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + HashFunction* hash; + SecureVector i_key, o_key; + }; + +} + + +namespace Botan { + +/** +* OpenPGP's S2K +*/ +class BOTAN_DLL OpenPGP_S2K : public PBKDF + { + public: + /** + * @param hash_in the hash function to use + */ + OpenPGP_S2K(HashFunction* hash_in) : hash(hash_in) {} + + ~OpenPGP_S2K() { delete hash; } + + std::string name() const + { + return "OpenPGP-S2K(" + hash->name() + ")"; + } + + PBKDF* clone() const + { + return new OpenPGP_S2K(hash->clone()); + } + + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + private: + HashFunction* hash; + }; + +} + + +namespace Botan { + +/** +* Lion is a block cipher construction designed by Ross Anderson and +* Eli Biham, described in "Two Practical and Provably Secure Block +* Ciphers: BEAR and LION". It has a variable block size and is +* designed to encrypt very large blocks (up to a megabyte) + +* http://www.cl.cam.ac.uk/~rja14/Papers/bear-lion.pdf +*/ +class BOTAN_DLL Lion : public BlockCipher + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + size_t block_size() const { return BLOCK_SIZE; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(2, 2*hash->output_length(), 2); + } + + void clear(); + std::string name() const; + BlockCipher* clone() const; + + /** + * @param hash the hash to use internally + * @param cipher the stream cipher to use internally + * @param block_size the size of the block to use + */ + Lion(HashFunction* hash, + StreamCipher* cipher, + size_t block_size); + + ~Lion() { delete hash; delete cipher; } + private: + void key_schedule(const byte[], size_t); + + const size_t BLOCK_SIZE, LEFT_SIZE, RIGHT_SIZE; + + HashFunction* hash; + StreamCipher* cipher; + SecureVector key1, key2; + }; + +} + + +namespace Botan { + +/** +* Skipjack, a NSA designed cipher used in Fortezza +*/ +class BOTAN_DLL Skipjack : public Block_Cipher_Fixed_Params<8, 10> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + std::string name() const { return "Skipjack"; } + BlockCipher* clone() const { return new Skipjack; } + + Skipjack() : FTAB(2560) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector FTAB; + }; + +} + + +namespace Botan { + +namespace FPE { + +/** +* Encrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the plaintext as a BigInt +* @param key a random key +* @param tweak will modify the ciphertext (think of as an IV) +*/ +BigInt BOTAN_DLL fe1_encrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const MemoryRegion& tweak); + +/** +* Decrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the ciphertext as a BigInt +* @param key is the key used for encryption +* @param tweak the same tweak used for encryption +*/ +BigInt BOTAN_DLL fe1_decrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const MemoryRegion& tweak); + +} + +} + + +namespace Botan { + +/** +* This class represents ECDH Public Keys. +*/ +class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey + { + public: + + ECDH_PublicKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDH_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Get this keys algorithm name. + * @return this keys algorithm name + */ + std::string algo_name() const { return "ECDH"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @return maximum number of input bits + */ + size_t max_input_bits() const { return domain().get_order().bits(); } + + /** + * @return public point value + */ + MemoryVector public_value() const + { return EC2OSP(public_point(), PointGFp::UNCOMPRESSED); } + + protected: + ECDH_PublicKey() {} + }; + +/** +* This class represents ECDH Private Keys. +*/ +class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey, + public EC_PrivateKey, + public PK_Key_Agreement_Key + { + public: + + ECDH_PrivateKey(const AlgorithmIdentifier& alg_id, + const MemoryRegion& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + ECDH_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + MemoryVector public_value() const + { return ECDH_PublicKey::public_value(); } + }; + +/** +* ECDH operation +*/ +class BOTAN_DLL ECDH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + ECDH_KA_Operation(const ECDH_PrivateKey& key); + + SecureVector agree(const byte w[], size_t w_len); + private: + const CurveGFp& curve; + const BigInt& cofactor; + BigInt l_times_priv; + }; + +} + + +namespace Botan { + +/** +* AES-128 +*/ +class BOTAN_DLL AES_128 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + AES_128() : EK(40), DK(40), ME(16), MD(16) {} + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-128"; } + BlockCipher* clone() const { return new AES_128; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector EK, DK; + SecureVector ME, MD; + }; + +/** +* AES-192 +*/ +class BOTAN_DLL AES_192 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + AES_192() : EK(48), DK(48), ME(16), MD(16) {} + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-192"; } + BlockCipher* clone() const { return new AES_192; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector EK, DK; + SecureVector ME, MD; + }; + +/** +* AES-256 +*/ +class BOTAN_DLL AES_256 : public Block_Cipher_Fixed_Params<16, 32> + { + public: + AES_256() : EK(56), DK(56), ME(16), MD(16) {} + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear(); + + std::string name() const { return "AES-256"; } + BlockCipher* clone() const { return new AES_256; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector EK, DK; + SecureVector ME, MD; + }; + +} + + +namespace Botan { + +/** +* Rivest's Package Tranform +* @param rng the random number generator to use +* @param cipher the block cipher to use +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len + cipher->BLOCK_SIZE bytes long) +*/ +void BOTAN_DLL aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]); + +/** +* Rivest's Package Tranform (Inversion) +* @param cipher the block cipher to use +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len - cipher->BLOCK_SIZE bytes long) +*/ +void BOTAN_DLL aont_unpackage(BlockCipher* cipher, + const byte input[], size_t input_len, + byte output[]); + +} + + +namespace Botan { + +/** +* Combines two hash functions using a Feistel scheme. Described in +* "On the Security of Hash Function Combiners", Anja Lehmann +*/ +class BOTAN_DLL Comb4P : public HashFunction + { + public: + /** + * @param h1 the first hash + * @param h2 the second hash + */ + Comb4P(HashFunction* h1, HashFunction* h2); + + ~Comb4P() { delete hash1; delete hash2; } + + size_t hash_block_size() const; + + size_t output_length() const + { + return hash1->output_length() + hash2->output_length(); + } + + HashFunction* clone() const + { + return new Comb4P(hash1->clone(), hash2->clone()); + } + + std::string name() const + { + return "Comb4P(" + hash1->name() + "," + hash2->name() + ")"; + } + + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + HashFunction* hash1; + HashFunction* hash2; + }; + +} + + +namespace Botan { + +/** +* A split secret, using the format from draft-mcgrew-tss-03 +*/ +class BOTAN_DLL RTSS_Share + { + public: + /** + * @param M the number of shares needed to reconstruct + * @param N the number of shares generated + * @param secret the secret to split + * @param secret_len the length of the secret + * @param identifier the 16 byte share identifier + * @param rng the random number generator to use + */ + static std::vector + split(byte M, byte N, + const byte secret[], u16bit secret_len, + const byte identifier[16], + RandomNumberGenerator& rng); + + /** + * @param shares the list of shares + */ + static SecureVector + reconstruct(const std::vector& shares); + + RTSS_Share() {} + + /** + * @param hex_input the share encoded in hexadecimal + */ + RTSS_Share(const std::string& hex_input); + + /** + * @return hex representation + */ + std::string to_string() const; + + /** + * @return share identifier + */ + byte share_id() const; + + /** + * @return size of this share in bytes + */ + size_t size() const { return contents.size(); } + + /** + * @return if this TSS share was initialized or not + */ + bool initialized() const { return (contents.size() > 0); } + private: + SecureVector contents; + }; + +} + + +namespace Botan { + +/** +* RC2 +*/ +class BOTAN_DLL RC2 : public Block_Cipher_Fixed_Params<8, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + /** + * Return the code of the effective key bits + * @param bits key length + * @return EKB code + */ + static byte EKB_code(size_t bits); + + void clear() { zeroise(K); } + std::string name() const { return "RC2"; } + BlockCipher* clone() const { return new RC2; } + + RC2() : K(64) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector K; + }; + +} + + +namespace Botan { + +/** +* DJB's Salsa20 (and XSalsa20) +*/ +class BOTAN_DLL Salsa20 : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == 8 || iv_len == 24); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + + void clear(); + std::string name() const; + StreamCipher* clone() const { return new Salsa20; } + + Salsa20() : state(16), buffer(64), position(0) {} + private: + void key_schedule(const byte key[], size_t key_len); + + SecureVector state; + SecureVector buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* RIPEMD-128 +*/ +class BOTAN_DLL RIPEMD_128 : public MDx_HashFunction + { + public: + std::string name() const { return "RIPEMD-128"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new RIPEMD_128; } + + void clear(); + + RIPEMD_128() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + private: + void compress_n(const byte[], size_t blocks); + void copy_out(byte[]); + + SecureVector M, digest; + }; + +} + + +namespace Botan { + +/** +* 24-bit cyclic redundancy check +*/ +class BOTAN_DLL CRC24 : public HashFunction + { + public: + std::string name() const { return "CRC24"; } + size_t output_length() const { return 3; } + HashFunction* clone() const { return new CRC24; } + + void clear() { crc = 0xB704CE; } + + CRC24() { clear(); } + ~CRC24() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u32bit crc; + }; + +} + + +namespace Botan { + +/** +* PKCS #5 v1 PBKDF, aka PBKDF1 +* Can only generate a key up to the size of the hash output. +* Unless needed for backwards compatability, use PKCS5_PBKDF2 +*/ +class BOTAN_DLL PKCS5_PBKDF1 : public PBKDF + { + public: + /** + * Create a PKCS #5 instance using the specified hash function. + * @param hash_in pointer to a hash function object to use + */ + PKCS5_PBKDF1(HashFunction* hash_in) : hash(hash_in) {} + + /** + * Copy constructor + * @param other the object to copy + */ + PKCS5_PBKDF1(const PKCS5_PBKDF1& other) : + PBKDF(), hash(other.hash->clone()) {} + + ~PKCS5_PBKDF1() { delete hash; } + + std::string name() const + { + return "PBKDF1(" + hash->name() + ")"; + } + + PBKDF* clone() const + { + return new PKCS5_PBKDF1(hash->clone()); + } + + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + private: + HashFunction* hash; + }; + +} + + +namespace Botan { + +/** +* This class represents X.509 Certificate Authorities (CAs). +*/ +class BOTAN_DLL X509_CA + { + public: + + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after); + + /** + * Get the certificate of this CA. + * @return CA certificate + */ + X509_Certificate ca_certificate() const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + u32bit next_update = 0) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector& new_entries, + RandomNumberGenerator& rng, + u32bit next_update = 0) const; + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const MemoryRegion& 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); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param hash_fn name of a hash function to use for signing + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn); + + ~X509_CA(); + private: + X509_CA(const X509_CA&) {} + X509_CA& operator=(const X509_CA&) { return (*this); } + + X509_CRL make_crl(const std::vector& entries, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const; + + AlgorithmIdentifier ca_sig_algo; + X509_Certificate cert; + PK_Signer* signer; + }; + +/** +* Choose the default signature format for a certain public key signature +* scheme. +* @param key will be the key to choose a padding scheme for +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +BOTAN_DLL PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +} + + +namespace Botan { + +namespace OIDS { + +/** +* Register an OID to string mapping. +* @param oid the oid to register +* @param name the name to be associated with the oid +*/ +BOTAN_DLL void add_oid(const OID& oid, const std::string& name); + +/** +* See if an OID exists in the internal table. +* @param oid the oid to check for +* @return true if the oid is registered +*/ +BOTAN_DLL bool have_oid(const std::string& oid); + +/** +* Resolve an OID +* @param oid the OID to look up +* @return name associated with this OID +*/ +BOTAN_DLL std::string lookup(const OID& oid); + +/** +* Find the OID to a name. The lookup will be performed in the +* general OID section of the configuration. +* @param name the name to resolve +* @return OID associated with the specified name +*/ +BOTAN_DLL OID lookup(const std::string& name); + +/** +* Tests whether the specified OID stands for the specified name. +* @param oid the OID to check +* @param name the name to check +* @return true if the specified OID stands for the specified name +*/ +BOTAN_DLL bool name_of(const OID& oid, const std::string& name); + +} + +} + + +namespace Botan { + +/** +* EAX Base Class +*/ +class BOTAN_DLL EAX_Base : public Keyed_Filter + { + public: + void set_key(const SymmetricKey& key); + void set_iv(const InitializationVector& iv); + + /** + * Set some additional data that is not included in the + * ciphertext but that will be authenticated. + * @param header the header contents + * @param header_len length of header in bytes + */ + void set_header(const byte header[], size_t header_len); + + /** + * @return name of this mode + */ + std::string name() const; + + bool valid_keylength(size_t key_len) const; + + /** + * EAX supports arbitrary IV lengths + */ + bool valid_iv_length(size_t) const { return true; } + + ~EAX_Base() { delete ctr; delete cmac; } + protected: + /** + * @param cipher the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Base(BlockCipher* cipher, size_t tag_size); + void start_msg(); + + /** + * The block size of the underlying cipher + */ + const size_t BLOCK_SIZE; + + /** + * The requested tag name + */ + const size_t TAG_SIZE; + + /** + * The name of the cipher + */ + std::string cipher_name; + + /** + * The stream cipher (CTR mode) + */ + StreamCipher* ctr; + + /** + * The MAC (CMAC) + */ + MessageAuthenticationCode* cmac; + + /** + * The MAC of the nonce + */ + SecureVector nonce_mac; + + /** + * The MAC of the header + */ + SecureVector header_mac; + + /** + * A buffer for CTR mode encryption + */ + SecureVector ctr_buf; + }; + +/** +* EAX Encryption +*/ +class BOTAN_DLL EAX_Encryption : public EAX_Base + { + public: + /** + * @param ciph the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Encryption(BlockCipher* ciph, size_t tag_size = 0) : + EAX_Base(ciph, tag_size) {} + + /** + * @param ciph the cipher to use + * @param key the key to use + * @param iv the initially set IV + * @param tag_size is how big the auth tag will be + */ + EAX_Encryption(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv, + size_t tag_size) : EAX_Base(ciph, tag_size) + { + set_key(key); + set_iv(iv); + } + private: + void write(const byte[], size_t); + void end_msg(); + }; + +/** +* EAX Decryption +*/ +class BOTAN_DLL EAX_Decryption : public EAX_Base + { + public: + /** + * @param ciph the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Decryption(BlockCipher* ciph, size_t tag_size = 0); + + /** + * @param ciph the cipher to use + * @param key the key to use + * @param iv the initially set IV + * @param tag_size is how big the auth tag will be + */ + EAX_Decryption(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv, + size_t tag_size = 0); + private: + void write(const byte[], size_t); + void do_write(const byte[], size_t); + void end_msg(); + + SecureVector queue; + size_t queue_start, queue_end; + }; + +} + + +namespace Botan { + +/** +* CMAC, also known as OMAC1 +*/ +class BOTAN_DLL CMAC : public MessageAuthenticationCode + { + public: + std::string name() const; + size_t output_length() const { return e->block_size(); } + MessageAuthenticationCode* clone() const; + + void clear(); + + Key_Length_Specification key_spec() const + { + return e->key_spec(); + } + + /** + * CMAC's polynomial doubling operation + * @param in the input + * @param polynomial the byte value of the polynomial + */ + static SecureVector poly_double(const MemoryRegion& in, + byte polynomial); + + /** + * @param cipher the underlying block cipher to use + */ + CMAC(BlockCipher* cipher); + ~CMAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + SecureVector buffer, state, B, P; + size_t position; + byte polynomial; + }; + +} + + +namespace Botan { + +/** +* Skein-512, a SHA-3 candidate +*/ +class BOTAN_DLL Skein_512 : public HashFunction + { + public: + /** + * @param output_bits the output size of Skein in bits + * @param personalization is a string that will paramaterize the + * hash output + */ + Skein_512(size_t output_bits = 512, + const std::string& personalization = ""); + + size_t hash_block_size() const { return 64; } + size_t output_length() const { return output_bits / 8; } + + HashFunction* clone() const; + std::string name() const; + void clear(); + private: + void add_data(const byte input[], size_t length); + void final_result(byte out[]); + + std::string personalization; + size_t output_bits; + + SecureVector H; + SecureVector T; + SecureVector buffer; + size_t buf_pos; + }; + +} + + +namespace Botan { + +/** +* CBC encryption with ciphertext stealing +*/ +class BOTAN_DLL CTS_Encryption : public Keyed_Filter + { + public: + std::string name() const { return cipher->name() + "/CTS"; } + + void set_iv(const InitializationVector&); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CTS_Encryption(BlockCipher* cipher); + + CTS_Encryption(BlockCipher* cipher, + const SymmetricKey& key, + const InitializationVector& iv); + + ~CTS_Encryption() { delete cipher; } + private: + void write(const byte[], size_t); + void end_msg(); + void encrypt(const byte[]); + + BlockCipher* cipher; + SecureVector buffer, state; + size_t position; + }; + +/** +* CBC decryption with ciphertext stealing +*/ +class BOTAN_DLL CTS_Decryption : public Keyed_Filter + { + public: + std::string name() const { return cipher->name() + "/CTS"; } + + void set_iv(const InitializationVector&); + + void set_key(const SymmetricKey& key) { cipher->set_key(key); } + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + CTS_Decryption(BlockCipher* cipher); + + CTS_Decryption(BlockCipher* cipher, + const SymmetricKey& key, + const InitializationVector& iv); + + ~CTS_Decryption() { delete cipher; } + private: + void write(const byte[], size_t); + void end_msg(); + void decrypt(const byte[]); + + BlockCipher* cipher; + SecureVector buffer, state, temp; + size_t position; + }; + +} + + +namespace Botan { + +/** +* Factory function for PBEs. +* @param algo_spec the name of the PBE algorithm to retrieve +* @return pointer to a PBE with randomly created parameters +*/ +BOTAN_DLL PBE* get_pbe(const std::string& algo_spec); + +/** +* Factory function for PBEs. +* @param pbe_oid the oid of the desired PBE +* @param params a DataSource providing the DER encoded parameters to use +* @return pointer to the PBE with the specified parameters +*/ +BOTAN_DLL PBE* get_pbe(const OID& pbe_oid, + DataSource& params); + +} + + +namespace Botan { + +/** +* Public key encryptor factory method. +* @deprecated Instantiate object from pubkey.h directly +* +* @param key the key that will work inside the encryptor +* @param eme determines the algorithm and encoding +* @return public key encryptor object +*/ +BOTAN_DEPRECATED("Instantiate object directly") +inline PK_Encryptor* get_pk_encryptor(const Public_Key& key, + const std::string& eme) + { + return new PK_Encryptor_EME(key, eme); + } + +/** +* Public key decryptor factory method. +* @deprecated Instantiate object from pubkey.h directly +* +* @param key the key that will work inside the decryptor +* @param eme determines the algorithm and encoding +* @return public key decryptor object +*/ +BOTAN_DEPRECATED("Instantiate object directly") +inline PK_Decryptor* get_pk_decryptor(const Private_Key& key, + const std::string& eme) + { + return new PK_Decryptor_EME(key, eme); + } + +/** +* Public key signer factory method. +* @deprecated Instantiate object from pubkey.h directly +* +* @param key the key that will work inside the signer +* @param emsa determines the algorithm, encoding and hash algorithm +* @param sig_format the signature format to be used +* @return public key signer object +*/ +BOTAN_DEPRECATED("Instantiate object directly") +inline PK_Signer* get_pk_signer(const Private_Key& key, + const std::string& emsa, + Signature_Format sig_format = IEEE_1363) + { + return new PK_Signer(key, emsa, sig_format); + } + +/** +* Public key verifier factory method. +* @deprecated Instantiate object from pubkey.h directly +* +* @param key the key that will work inside the verifier +* @param emsa determines the algorithm, encoding and hash algorithm +* @param sig_format the signature format to be used +* @return public key verifier object +*/ +BOTAN_DEPRECATED("Instantiate object directly") +inline PK_Verifier* get_pk_verifier(const Public_Key& key, + const std::string& emsa, + Signature_Format sig_format = IEEE_1363) + { + return new PK_Verifier(key, emsa, sig_format); + } + +/** +* Public key key agreement factory method. +* @deprecated Instantiate object from pubkey.h directly +* +* @param key the key that will work inside the key agreement +* @param kdf the kdf algorithm to use +* @return key agreement algorithm +*/ +BOTAN_DEPRECATED("Instantiate object directly") +inline PK_Key_Agreement* get_pk_kas(const PK_Key_Agreement_Key& key, + const std::string& kdf) + { + return new PK_Key_Agreement(key, kdf); + } + +} + + +namespace Botan { + +/** +* IDEA +*/ +class BOTAN_DLL IDEA : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); zeroise(DK); } + std::string name() const { return "IDEA"; } + BlockCipher* clone() const { return new IDEA; } + + IDEA() : EK(52), DK(52) {} + protected: + /** + * @return const reference to encryption subkeys + */ + const SecureVector& get_EK() const { return EK; } + + /** + * @return const reference to decryption subkeys + */ + const SecureVector& get_DK() const { return DK; } + + private: + void key_schedule(const byte[], size_t); + SecureVector EK, DK; + }; + +} + + +namespace Botan { + +/** +* Return the PKCS #1 hash identifier +* @see RFC 3447 section 9.2 +* @param hash_name the name of the hash function +* @return byte sequence identifying the hash +* @throw Invalid_Argument if the hash has no known PKCS #1 hash id +*/ +BOTAN_DLL MemoryVector pkcs_hash_id(const std::string& hash_name); + +/** +* Return the IEEE 1363 hash identifier +* @param hash_name the name of the hash function +* @return byte code identifying the hash, or 0 if not known +*/ +BOTAN_DLL byte ieee1363_hash_id(const std::string& hash_name); + +} + + +namespace Botan { + +/** +* MGF1 from PKCS #1 v2.0 +*/ +class BOTAN_DLL MGF1 : public MGF + { + public: + void mask(const byte[], size_t, byte[], size_t) const; + + /** + MGF1 constructor: takes ownership of hash + */ + MGF1(HashFunction* hash); + + ~MGF1(); + private: + HashFunction* hash; + }; + +} + + +namespace Botan { + +/** +* IEEE P1619 XTS Encryption +*/ +class BOTAN_DLL XTS_Encryption : public Keyed_Filter, + private Buffered_Filter + { + public: + void set_key(const SymmetricKey& key); + void set_iv(const InitializationVector& iv); + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + std::string name() const; + + XTS_Encryption(BlockCipher* ciph); + + XTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv); + + ~XTS_Encryption() { delete cipher; delete cipher2; } + private: + void write(const byte[], size_t); + void end_msg(); + + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + BlockCipher* cipher; + BlockCipher* cipher2; + SecureVector tweak; + }; + +/** +* IEEE P1619 XTS Encryption +*/ +class BOTAN_DLL XTS_Decryption : public Keyed_Filter, + private Buffered_Filter + { + public: + void set_key(const SymmetricKey& key); + void set_iv(const InitializationVector& iv); + + bool valid_keylength(size_t key_len) const + { return cipher->valid_keylength(key_len); } + + bool valid_iv_length(size_t iv_len) const + { return (iv_len == cipher->block_size()); } + + std::string name() const; + + XTS_Decryption(BlockCipher* ciph); + + XTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv); + + ~XTS_Decryption() { delete cipher; delete cipher2; } + private: + void write(const byte[], size_t); + void end_msg(); + + void buffered_block(const byte input[], size_t input_length); + void buffered_final(const byte input[], size_t input_length); + + BlockCipher* cipher; + BlockCipher* cipher2; + SecureVector tweak; + }; + +} + + +namespace Botan { + +/** +* Struct representing a particular date and time +*/ +struct BOTAN_DLL calendar_point + { + /** The year */ + u32bit year; + + /** The month, 1 through 12 for Jan to Dec */ + byte month; + + /** The day of the month, 1 through 31 (or 28 or 30 based on month */ + byte day; + + /** Hour in 24-hour form, 0 to 23 */ + byte hour; + + /** Minutes in the hour, 0 to 60 */ + byte minutes; + + /** Seconds in the minute, 0 to 60, but might be slightly + larger to deal with leap seconds on some systems + */ + byte seconds; + + /** + * Initialize a calendar_point + * @param y the year + * @param mon the month + * @param d the day + * @param h the hour + * @param min the minute + * @param sec the second + */ + calendar_point(u32bit y, byte mon, byte d, byte h, byte min, byte sec) : + year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {} + }; + +/** +* @param time_point a time point from the system clock +* @return calendar_point object representing this time point +*/ +BOTAN_DLL calendar_point calendar_value(u64bit time_point); + +/** +* @return seconds resolution timestamp, unknown epoch +*/ +BOTAN_DLL u64bit system_time(); + +/** +* @return nanoseconds resolution timestamp, unknown epoch +*/ +BOTAN_DLL u64bit get_nanoseconds_clock(); + +} + + +namespace Botan { + +/** +* EMSA-Raw - sign inputs directly +* Don't use this unless you know what you are doing. +*/ +class BOTAN_DLL EMSA_Raw : public EMSA + { + private: + void update(const byte[], size_t); + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator&); + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + + SecureVector message; + }; + +} + + +namespace Botan { + +/** +* Perform base64 encoding +* @param output an array of at least input_length*4/3 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_encode(char output[], + const byte input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs); + +/** +* Perform base64 encoding +* @param input some input +* @param input_length length of input in bytes +* @return base64adecimal representation of input +*/ +std::string BOTAN_DLL base64_encode(const byte input[], + size_t input_length); + +/** +* Perform base64 encoding +* @param input some input +* @return base64adecimal representation of input +*/ +std::string BOTAN_DLL base64_encode(const MemoryRegion& input); + +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length/3*4 bytes +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +SecureVector BOTAN_DLL base64_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +SecureVector BOTAN_DLL base64_decode(const std::string& input, + bool ignore_ws = true); + +} + + +namespace Botan { + +/** +* PRF used in TLS 1.0/1.1 +*/ +class BOTAN_DLL TLS_PRF : public KDF + { + public: + SecureVector derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const; + + std::string name() const { return "TLS-PRF"; } + KDF* clone() const { return new TLS_PRF; } + + TLS_PRF(); + ~TLS_PRF(); + private: + MessageAuthenticationCode* hmac_md5; + MessageAuthenticationCode* hmac_sha1; + }; + +/** +* PRF used in TLS 1.2 +*/ +class BOTAN_DLL TLS_12_PRF : public KDF + { + public: + SecureVector derive(size_t key_len, + const byte secret[], size_t secret_len, + const byte seed[], size_t seed_len) const; + + std::string name() const { return "TLSv12-PRF(" + hmac->name() + ")"; } + KDF* clone() const { return new TLS_12_PRF(hmac->clone()); } + + TLS_12_PRF(MessageAuthenticationCode* hmac); + ~TLS_12_PRF(); + private: + MessageAuthenticationCode* hmac; + }; + +} + + +namespace Botan { + +/** +* EMSA4 aka PSS-R +*/ +class BOTAN_DLL EMSA4 : public EMSA + { + public: + /** + * @param hash the hash object to use + */ + EMSA4(HashFunction* hash); + + /** + * @param hash the hash object to use + * @param salt_size the size of the salt to use in bytes + */ + EMSA4(HashFunction* hash, size_t salt_size); + + ~EMSA4() { delete hash; delete mgf; } + private: + void update(const byte[], size_t); + SecureVector raw_data(); + + SecureVector encoding_of(const MemoryRegion&, size_t, + RandomNumberGenerator& rng); + bool verify(const MemoryRegion&, const MemoryRegion&, + size_t); + + size_t SALT_SIZE; + HashFunction* hash; + const MGF* mgf; + }; + +} + + +namespace Botan { + +/** +* Camellia-128 +*/ +class BOTAN_DLL Camellia_128 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { SK.clear(); } + std::string name() const { return "Camellia-128"; } + BlockCipher* clone() const { return new Camellia_128; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector SK; + }; + +/** +* Camellia-192 +*/ +class BOTAN_DLL Camellia_192 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { SK.clear(); } + std::string name() const { return "Camellia-192"; } + BlockCipher* clone() const { return new Camellia_192; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector SK; + }; + +/** +* Camellia-256 +*/ +class BOTAN_DLL Camellia_256 : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { SK.clear(); } + std::string name() const { return "Camellia-256"; } + BlockCipher* clone() const { return new Camellia_256; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector SK; + }; + +} + + +namespace Botan { + +/** +* MD4 +*/ +class BOTAN_DLL MD4 : public MDx_HashFunction + { + public: + std::string name() const { return "MD4"; } + size_t output_length() const { return 16; } + HashFunction* clone() const { return new MD4; } + + void clear(); + + MD4() : MDx_HashFunction(64, false, true), M(16), digest(4) + { clear(); } + protected: + void compress_n(const byte input[], size_t blocks); + void copy_out(byte[]); + + /** + * The message buffer, exposed for use by subclasses (x86 asm) + */ + SecureVector M; + + /** + * The digest value, exposed for use by subclasses (x86 asm) + */ + SecureVector digest; + }; + +} + + +namespace Botan { + +/** +* Turing +*/ +class BOTAN_DLL Turing : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + void set_iv(const byte iv[], size_t iv_length); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len % 4 == 0 && iv_len <= 16); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(4, 32, 4); + } + + void clear(); + std::string name() const { return "Turing"; } + StreamCipher* clone() const { return new Turing; } + + Turing() : S0(256), S1(256), S2(256), S3(256), + R(17), buffer(340), position(0) {} + + private: + void key_schedule(const byte[], size_t); + void generate(); + + static u32bit fixedS(u32bit); + + static const u32bit Q_BOX[256]; + static const byte SBOX[256]; + + SecureVector S0, S1, S2, S3; + SecureVector R; + SecureVector K; + SecureVector buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* SRP6a Client side +* @param username the username we are attempting login for +* @param password the password we are attempting to use +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +* @param salt is the salt value sent by the server +* @param B is the server's public value +* @param rng is a random number generator +* +* @return (A,K) the client public key and the shared secret key +*/ +std::pair +BOTAN_DLL srp6_client_agree(const std::string& username, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const MemoryRegion& salt, + const BigInt& B, + RandomNumberGenerator& rng); + +/** +* Generate a new SRP-6 verifier +* @param identifier a username or other client identifier +* @param password the secret used to authenticate user +* @param salt a randomly chosen value, at least 128 bits long +*/ +BigInt BOTAN_DLL generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const MemoryRegion& salt, + const std::string& group_id, + const std::string& hash_id); + +/** +* Return the group id for this SRP param set, or else thrown an +* exception +*/ +std::string BOTAN_DLL srp6_group_identifier(const BigInt& N, const BigInt& g); + +/** +* Represents a SRP-6a server session +*/ +class BOTAN_DLL SRP6_Server_Session + { + public: + /** + * Server side step 1 + * @param v the verification value saved from client registration + */ + BigInt step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng); + + SymmetricKey step2(const BigInt& A); + + private: + std::string hash_id; + BigInt B, b, v, S, p; + size_t p_bytes; + }; + +} + + +namespace Botan { + +/** +* SAFER-SK +*/ +class BOTAN_DLL SAFER_SK : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); } + std::string name() const; + BlockCipher* clone() const; + + /** + * @param rounds the number of rounds to use - must be between 1 + * and 13 + */ + SAFER_SK(size_t rounds); + private: + size_t get_rounds() const { return (EK.size() - 8) / 16; } + void key_schedule(const byte[], size_t); + + SecureVector EK; + }; + +} + + +namespace Botan { + +/** +* CAST-128 +*/ +class BOTAN_DLL CAST_128 : public Block_Cipher_Fixed_Params<8, 11, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(MK); zeroise(RK); } + std::string name() const { return "CAST-128"; } + BlockCipher* clone() const { return new CAST_128; } + + CAST_128() : MK(16), RK(16) {} + private: + void key_schedule(const byte[], size_t); + + static void cast_ks(MemoryRegion& ks, + MemoryRegion& user_key); + + static const u32bit S5[256]; + static const u32bit S6[256]; + static const u32bit S7[256]; + static const u32bit S8[256]; + + SecureVector MK, RK; + }; + +extern const u32bit CAST_SBOX1[256]; +extern const u32bit CAST_SBOX2[256]; +extern const u32bit CAST_SBOX3[256]; +extern const u32bit CAST_SBOX4[256]; + +} + + +namespace Botan { + +/** +* PKCS #5 v2.0 PBE +*/ +class BOTAN_DLL PBE_PKCS5v20 : public PBE + { + public: + /** + * @param cipher names a block cipher + * @return true iff PKCS #5 knows how to use this cipher + */ + static bool known_cipher(const std::string& cipher); + + std::string name() const; + + void write(const byte[], size_t); + void start_msg(); + void end_msg(); + + /** + * Load a PKCS #5 v2.0 encrypted stream + * @param input is the input source + */ + PBE_PKCS5v20(DataSource& input); + + /** + * @param cipher the block cipher to use + * @param hash the hash function to use + */ + PBE_PKCS5v20(BlockCipher* cipher, HashFunction* hash); + + ~PBE_PKCS5v20(); + private: + void set_key(const std::string&); + void new_params(RandomNumberGenerator& rng); + MemoryVector encode_params() const; + void decode_params(DataSource&); + OID get_oid() const; + + void flush_pipe(bool); + + Cipher_Dir direction; + BlockCipher* block_cipher; + HashFunction* hash_function; + SecureVector salt, key, iv; + size_t iterations, key_length; + Pipe pipe; + }; + +} + + +namespace Botan { + +/** +* Algorithm benchmark +* @param name the name of the algorithm to test (cipher, hash, or MAC) +* @param af the algorithm factory used to create objects +* @param rng the rng to use to generate random inputs +* @param milliseconds total time for the benchmark to run +* @param buf_size size of buffer to benchmark against, in KiB +* @return results a map from provider to speed in mebibytes per second +*/ +std::map +BOTAN_DLL algorithm_benchmark(const std::string& name, + Algorithm_Factory& af, + RandomNumberGenerator& rng, + u32bit milliseconds, + size_t buf_size); + +} + + +namespace Botan { + +/** +* CBC-MAC +*/ +class BOTAN_DLL CBC_MAC : public MessageAuthenticationCode + { + public: + std::string name() const; + MessageAuthenticationCode* clone() const; + size_t output_length() const { return e->block_size(); } + void clear(); + + Key_Length_Specification key_spec() const + { + return e->key_spec(); + } + + /** + * @param cipher the underlying block cipher to use + */ + CBC_MAC(BlockCipher* cipher); + ~CBC_MAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + SecureVector state; + size_t position; + }; + +} + + +namespace Botan { + +/** +* MARS, IBM's candidate for AES +*/ +class BOTAN_DLL MARS : public Block_Cipher_Fixed_Params<16, 16, 32, 4> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(EK); } + std::string name() const { return "MARS"; } + BlockCipher* clone() const { return new MARS; } + + MARS() : EK(40) {} + private: + void key_schedule(const byte[], size_t); + + SecureVector EK; + }; + +} + + +namespace Botan { + +/** +* PKCS #5 PBKDF2 +*/ +class BOTAN_DLL PKCS5_PBKDF2 : public PBKDF + { + public: + std::string name() const + { + return "PBKDF2(" + mac->name() + ")"; + } + + PBKDF* clone() const + { + return new PKCS5_PBKDF2(mac->clone()); + } + + OctetString derive_key(size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + + /** + * Create a PKCS #5 instance using the specified message auth code + * @param mac_fn the MAC to use + */ + PKCS5_PBKDF2(MessageAuthenticationCode* mac_fn) : mac(mac_fn) {} + + /** + * Destructor + */ + ~PKCS5_PBKDF2() { delete mac; } + private: + MessageAuthenticationCode* mac; + }; + +} + + +namespace Botan { + +class Algorithm_Factory; + +/** +* Encrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the plaintext key to encrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key encrypted under kek +*/ +SecureVector BOTAN_DLL rfc3394_keywrap(const MemoryRegion& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +/** +* Decrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the encrypted key to decrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key decrypted under kek +*/ +SecureVector BOTAN_DLL rfc3394_keyunwrap(const MemoryRegion& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +} + + +namespace Botan { + +/** +* DLIES Encryption +*/ +class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor + { + public: + DLIES_Encryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + ~DLIES_Encryptor(); + + void set_other_key(const MemoryRegion&); + private: + SecureVector enc(const byte[], size_t, + RandomNumberGenerator&) const; + size_t maximum_input_size() const; + + SecureVector other_key, my_key; + + PK_Key_Agreement ka; + KDF* kdf; + MessageAuthenticationCode* mac; + size_t mac_keylen; + }; + +/** +* DLIES Decryption +*/ +class BOTAN_DLL DLIES_Decryptor : public PK_Decryptor + { + public: + DLIES_Decryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + ~DLIES_Decryptor(); + + private: + SecureVector dec(const byte[], size_t) const; + + SecureVector my_key; + + PK_Key_Agreement ka; + KDF* kdf; + MessageAuthenticationCode* mac; + size_t mac_keylen; + }; + +} + + +namespace Botan { + +/** +* Output Feedback Mode +*/ +class BOTAN_DLL OFB : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len <= permutation->block_size()); } + + Key_Length_Specification key_spec() const + { + return permutation->key_spec(); + } + + std::string name() const; + + OFB* clone() const + { return new OFB(permutation->clone()); } + + void clear(); + + /** + * @param cipher the underlying block cipher to use + */ + OFB(BlockCipher* cipher); + ~OFB(); + private: + void key_schedule(const byte key[], size_t key_len); + + BlockCipher* permutation; + SecureVector buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* Blowfish +*/ +class BOTAN_DLL Blowfish : public Block_Cipher_Fixed_Params<8, 1, 56> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + /** + * Modified EKSBlowfish key schedule, used for bcrypt password hashing + */ + void eks_key_schedule(const byte key[], size_t key_length, + const byte salt[16], size_t workfactor); + + void clear(); + std::string name() const { return "Blowfish"; } + BlockCipher* clone() const { return new Blowfish; } + + Blowfish() : S(1024), P(18) {} + private: + void key_schedule(const byte key[], size_t length); + + void key_expansion(const byte key[], + size_t key_length, + const byte salt[16]); + + void generate_sbox(MemoryRegion& box, + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const; + + static const u32bit P_INIT[18]; + static const u32bit S_INIT[1024]; + + SecureVector S; + SecureVector P; + }; + +} + + +namespace Botan { + +/** +* The Adler32 checksum, used in zlib +*/ +class BOTAN_DLL Adler32 : public HashFunction + { + public: + std::string name() const { return "Adler32"; } + size_t output_length() const { return 4; } + HashFunction* clone() const { return new Adler32; } + + void clear() { S1 = 1; S2 = 0; } + + Adler32() { clear(); } + ~Adler32() { clear(); } + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + u16bit S1, S2; + }; + +} + + +namespace Botan { + +/** +* Parallel Hashes +*/ +class BOTAN_DLL Parallel : public HashFunction + { + public: + void clear(); + std::string name() const; + HashFunction* clone() const; + + size_t output_length() const; + + /** + * @param hashes a set of hashes to compute in parallel + */ + Parallel(const std::vector& hashes); + ~Parallel(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + std::vector hashes; + }; + +} + + +namespace Botan { + +/** +* RC5 +*/ +class BOTAN_DLL RC5 : public Block_Cipher_Fixed_Params<8, 1, 32> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { zeroise(S); } + std::string name() const; + BlockCipher* clone() const { return new RC5(get_rounds()); } + + /** + * @param rounds the number of RC5 rounds to run. Must be between + * 8 and 32 and a multiple of 4. + */ + RC5(size_t rounds); + private: + size_t get_rounds() const { return (S.size() - 2) / 2; } + + void key_schedule(const byte[], size_t); + + SecureVector S; + }; + +} + + +namespace Botan { + +/** +* Run a set of self tests on some basic algorithms like AES and SHA-1 +* @param af an algorithm factory +* @throws Self_Test_Error if a failure occured +*/ +BOTAN_DLL void confirm_startup_self_tests(Algorithm_Factory& af); + +/** +* Run a set of self tests on some basic algorithms like AES and SHA-1 +* @param af an algorithm factory +* @returns false if a failure occured, otherwise true +*/ +BOTAN_DLL bool passes_self_tests(Algorithm_Factory& af); + +/** +* Run a set of algorithm KATs (known answer tests) +* @param algo_name the algorithm we are testing +* @param vars a set of input variables for this test, all + hex encoded. Keys used: "input", "output", "key", and "iv" +* @param af an algorithm factory +* @returns map from provider name to test result for that provider +*/ +BOTAN_DLL std::map +algorithm_kat(const SCAN_Name& algo_name, + const std::map& vars, + Algorithm_Factory& af); + +} + + +namespace Botan { + +/** +* Noekeon implementation using SIMD operations +*/ +class BOTAN_DLL Noekeon_SIMD : public Noekeon + { + public: + size_t parallelism() const { return 4; } + + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + BlockCipher* clone() const { return new Noekeon_SIMD; } + }; + +} + + +namespace Botan { + +/** +* PKCS #5 v1.5 PBE +*/ +class BOTAN_DLL PBE_PKCS5v15 : public PBE + { + public: + std::string name() const; + + void write(const byte[], size_t); + void start_msg(); + void end_msg(); + + /** + * @param cipher the block cipher to use (DES or RC2) + * @param hash the hash function to use + * @param direction are we encrypting or decrypting + */ + PBE_PKCS5v15(BlockCipher* cipher, + HashFunction* hash, + Cipher_Dir direction); + + ~PBE_PKCS5v15(); + private: + void set_key(const std::string&); + void new_params(RandomNumberGenerator& rng); + MemoryVector encode_params() const; + void decode_params(DataSource&); + OID get_oid() const; + + void flush_pipe(bool); + + Cipher_Dir direction; + BlockCipher* block_cipher; + HashFunction* hash_function; + + SecureVector salt, key, iv; + size_t iterations; + Pipe pipe; + }; + +} + + +namespace Botan { + +/** +* CTR-BE (Counter mode, big-endian) +*/ +class BOTAN_DLL CTR_BE : public StreamCipher + { + public: + void cipher(const byte in[], byte out[], size_t length); + + void set_iv(const byte iv[], size_t iv_len); + + bool valid_iv_length(size_t iv_len) const + { return (iv_len <= permutation->block_size()); } + + Key_Length_Specification key_spec() const + { + return permutation->key_spec(); + } + + std::string name() const; + + CTR_BE* clone() const + { return new CTR_BE(permutation->clone()); } + + void clear(); + + /** + * @param cipher the underlying block cipher to use + */ + CTR_BE(BlockCipher* cipher); + ~CTR_BE(); + private: + void key_schedule(const byte key[], size_t key_len); + void increment_counter(); + + BlockCipher* permutation; + SecureVector counter, buffer; + size_t position; + }; + +} + + +namespace Botan { + +/** +* Randpool +*/ +class BOTAN_DLL Randpool : public RandomNumberGenerator + { + public: + void randomize(byte[], size_t); + bool is_seeded() const { return seeded; } + void clear(); + std::string name() const; + + void reseed(size_t bits_to_collect); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte input[], size_t length); + + /** + * @param cipher a block cipher to use + * @param mac a message authentication code to use + * @param pool_blocks how many cipher blocks to use for the pool + * @param iterations_before_reseed how many times we'll use the + * internal state to generate output before reseeding + */ + Randpool(BlockCipher* cipher, + MessageAuthenticationCode* mac, + size_t pool_blocks = 32, + size_t iterations_before_reseed = 128); + + ~Randpool(); + private: + void update_buffer(); + void mix_pool(); + + size_t ITERATIONS_BEFORE_RESEED, POOL_BLOCKS; + BlockCipher* cipher; + MessageAuthenticationCode* mac; + + std::vector entropy_sources; + SecureVector pool, buffer, counter; + bool seeded; + }; + +} + + +namespace Botan { + +/** +* PRF used in SSLv3 +*/ +class BOTAN_DLL SSL3_PRF : public KDF + { + public: + SecureVector derive(size_t, const byte[], size_t, + const byte[], size_t) const; + + std::string name() const { return "SSL3-PRF"; } + KDF* clone() const { return new SSL3_PRF; } + }; + +} + + +namespace Botan { + +/** +* DES/3DES-based MAC from ANSI X9.19 +*/ +class BOTAN_DLL ANSI_X919_MAC : public MessageAuthenticationCode + { + public: + void clear(); + std::string name() const; + size_t output_length() const { return e->block_size(); } + MessageAuthenticationCode* clone() const; + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(8, 16, 8); + } + + /** + * @param cipher the underlying block cipher to use + */ + ANSI_X919_MAC(BlockCipher* cipher); + ~ANSI_X919_MAC(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + void key_schedule(const byte[], size_t); + + BlockCipher* e; + BlockCipher* d; + SecureVector state; + size_t position; + }; + +} + +#endif // USE_SYSTEM_BOTAN +#endif // BOTAN_AMALGAMATION_H__ diff --git a/client/3rd/QtSsh/src/botan/botan.pri b/client/3rd/QtSsh/src/botan/botan.pri new file mode 100644 index 00000000..c0d02874 --- /dev/null +++ b/client/3rd/QtSsh/src/botan/botan.pri @@ -0,0 +1,50 @@ +INCLUDEPATH *= $$PWD/.. +HEADERS += $$PWD/botan.h + +SOURCES += $$PWD/botan.cpp + +CONFIG += exceptions + +DEPENDPATH += . + +DEFINES += BOTAN_DLL= +unix:DEFINES += BOTAN_TARGET_OS_HAS_GETTIMEOFDAY BOTAN_HAS_ALLOC_MMAP \ + BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM BOTAN_HAS_ENTROPY_SRC_EGD BOTAN_HAS_ENTROPY_SRC_FTW \ + BOTAN_HAS_ENTROPY_SRC_UNIX BOTAN_HAS_MUTEX_PTHREAD BOTAN_HAS_PIPE_UNIXFD_IO +*linux*:DEFINES += BOTAN_TARGET_OS_IS_LINUX BOTAN_TARGET_OS_HAS_CLOCK_GETTIME \ + BOTAN_TARGET_OS_HAS_DLOPEN BOTAN_TARGET_OS_HAS_GMTIME_R BOTAN_TARGET_OS_HAS_POSIX_MLOCK \ + BOTAN_HAS_DYNAMICALLY_LOADED_ENGINE BOTAN_HAS_DYNAMIC_LOADER +macx:DEFINES += BOTAN_TARGET_OS_IS_DARWIN +*g++*:DEFINES += BOTAN_BUILD_COMPILER_IS_GCC +*clang*:DEFINES += BOTAN_BUILD_COMPILER_IS_CLANG +*icc*:DEFINES += BOTAN_BUILD_COMPILER_IS_INTEL + +CONFIG(x86_64):DEFINES += BOTAN_TARGET_ARCH_IS_X86_64 + +win32 { + DEFINES += BOTAN_TARGET_OS_IS_WINDOWS \ + BOTAN_TARGET_OS_HAS_LOADLIBRARY BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME \ + BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK \ + BOTAN_HAS_ENTROPY_SRC_CAPI BOTAN_HAS_ENTROPY_SRC_WIN32 \ + BOTAN_HAS_MUTEX_WIN32 + + msvc { + QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHs + QMAKE_CXXFLAGS += -wd4251 -wd4290 -wd4250 -wd4297 -wd4267 -wd4334 + DEFINES += BOTAN_BUILD_COMPILER_IS_MSVC BOTAN_TARGET_OS_HAS_GMTIME_S _SCL_SECURE_NO_WARNINGS + } else { + QMAKE_CFLAGS += -fpermissive -finline-functions -Wno-long-long + QMAKE_CXXFLAGS += -fpermissive -finline-functions -Wno-long-long + } + LIBS += -ladvapi32 -luser32 +} + +unix:*-g++* { + QMAKE_CFLAGS += -fPIC -fpermissive -finline-functions -Wno-long-long + QMAKE_CXXFLAGS += -fPIC -fpermissive -finline-functions -Wno-long-long +} + +linux*|freebsd* { + LIBS += -lrt $$QMAKE_LIBS_DYNLOAD +} + diff --git a/client/3rd/QtSsh/src/botan/configure.py b/client/3rd/QtSsh/src/botan/configure.py new file mode 100644 index 00000000..71d2a3d3 --- /dev/null +++ b/client/3rd/QtSsh/src/botan/configure.py @@ -0,0 +1,1881 @@ +#!/usr/bin/env python + +""" +Configuration program for botan (http://botan.randombit.net/) + (C) 2009-2011 Jack Lloyd + Distributed under the terms of the Botan license + +Tested with CPython 2.6, 2.7, 3.1 and PyPy 1.5 + +Python 2.5 works if you change the exception catching syntax: + perl -pi -e 's/except (.*) as (.*):/except $1, $2:/g' configure.py + +Jython - Target detection does not work (use --os and --cpu) + +CPython 2.4 and earlier are not supported + +Has not been tested with IronPython +""" + +import sys +import os +import os.path +import platform +import re +import shlex +import shutil +import string +import subprocess +import logging +import getpass +import time +import errno +import optparse + +# Avoid useless botan_version.pyc (Python 2.6 or higher) +if 'dont_write_bytecode' in sys.__dict__: + sys.dont_write_bytecode = True + +import botan_version + +def flatten(l): + return sum(l, []) + +def get_vc_revision(): + try: + mtn = subprocess.Popen(['mtn', 'automate', 'heads'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + + (stdout, stderr) = mtn.communicate() + + if mtn.returncode != 0: + logging.debug('Error getting rev from monotone - %d (%s)' + % (mtn.returncode, stderr)) + return 'unknown' + + rev = str(stdout).strip() + logging.debug('Monotone reported revision %s' % (rev)) + + return 'mtn:' + rev + except OSError as e: + logging.debug('Error getting rev from monotone - %s' % (e[1])) + return 'unknown' + except Exception as e: + logging.debug('Error getting rev from monotone - %s' % (e)) + return 'unknown' + + +class BuildConfigurationInformation(object): + + """ + Version information + """ + version_major = botan_version.release_major + version_minor = botan_version.release_minor + version_patch = botan_version.release_patch + version_so_rev = botan_version.release_so_abi_rev + + version_datestamp = botan_version.release_datestamp + + version_vc_rev = botan_version.release_vc_rev + version_string = '%d.%d.%d' % (version_major, version_minor, version_patch) + + """ + Constructor + """ + def __init__(self, options, modules): + + if self.version_vc_rev is None: + self.version_vc_rev = get_vc_revision() + + self.build_dir = os.path.join(options.with_build_dir, 'build') + + self.checkobj_dir = os.path.join(self.build_dir, 'checks') + self.libobj_dir = os.path.join(self.build_dir, 'lib') + + self.python_dir = os.path.join(options.src_dir, 'wrap', 'python') + + self.boost_python = options.boost_python + + self.doc_output_dir = os.path.join(self.build_dir, 'docs') + + self.pyobject_dir = os.path.join(self.build_dir, 'python') + + self.include_dir = os.path.join(self.build_dir, 'include') + self.botan_include_dir = os.path.join(self.include_dir, 'botan') + self.internal_include_dir = os.path.join(self.botan_include_dir, 'internal') + + self.sources = sorted(flatten([mod.sources() for mod in modules])) + self.internal_headers = sorted(flatten([m.internal_headers() for m in modules])) + + if options.via_amalgamation: + self.build_sources = ['botan_all.cpp'] + self.build_internal_headers = [] + else: + self.build_sources = self.sources + self.build_internal_headers = self.internal_headers + + self.public_headers = sorted(flatten([m.public_headers() for m in modules])) + + checks_dir = os.path.join(options.base_dir, 'checks') + + self.check_sources = sorted( + [os.path.join(checks_dir, file) for file in os.listdir(checks_dir) + if file.endswith('.cpp')]) + + self.python_sources = sorted( + [os.path.join(self.python_dir, file) + for file in os.listdir(self.python_dir) + if file.endswith('.cpp')]) + + self.manual_dir = os.path.join(self. doc_output_dir, 'manual') + + def build_doc_commands(): + yield '$(COPY) readme.txt %s' % (self.doc_output_dir) + + if options.with_sphinx: + yield 'sphinx-build $(SPHINX_OPTS) -b html doc %s' % ( + self.manual_dir) + else: + yield '$(COPY) doc/*.txt %s' % (self.manual_dir) + + if options.with_doxygen: + yield 'doxygen %s/botan.doxy' % (self.build_dir) + + self.build_doc_commands = '\n'.join(['\t' + s for s in build_doc_commands()]) + + def build_dirs(): + yield self.checkobj_dir + yield self.libobj_dir + yield self.botan_include_dir + yield self.internal_include_dir + yield os.path.join(self.doc_output_dir, 'manual') + if options.with_doxygen: + yield os.path.join(self.doc_output_dir, 'doxygen') + + if self.boost_python: + yield self.pyobject_dir + + self.build_dirs = list(build_dirs()) + + def pkg_config_file(self): + return 'botan-%d.%d.pc' % (self.version_major, + self.version_minor) + + def config_shell_script(self): + return 'botan-config-%d.%d' % (self.version_major, + self.version_minor) + + def username(self): + return getpass.getuser() + + def hostname(self): + return platform.node() + + def timestamp(self): + return time.ctime() + +""" +Handle command line options +""" +def process_command_line(args): + + parser = optparse.OptionParser( + formatter = optparse.IndentedHelpFormatter(max_help_position = 50), + version = BuildConfigurationInformation.version_string) + + parser.add_option('--verbose', action='store_true', default=False, + help='Show debug messages') + parser.add_option('--quiet', action='store_true', default=False, + help='Show only warnings and errors') + + target_group = optparse.OptionGroup(parser, 'Target options') + + target_group.add_option('--cpu', + help='set the target processor type/model') + + target_group.add_option('--os', + help='set the target operating system') + + target_group.add_option('--cc', dest='compiler', + help='set the desired build compiler') + + target_group.add_option('--cc-bin', dest='compiler_binary', + metavar='BINARY', + help='set the name of the compiler binary') + + target_group.add_option('--with-endian', metavar='ORDER', default=None, + help='override guess of CPU byte order') + + target_group.add_option('--with-unaligned-mem', + dest='unaligned_mem', action='store_true', + default=None, + help='enable unaligned memory accesses') + + target_group.add_option('--without-unaligned-mem', + dest='unaligned_mem', action='store_false', + help=optparse.SUPPRESS_HELP) + + for isa_extn_name in ['SSE2', 'SSSE3', 'AltiVec', 'AES-NI', 'movbe']: + isa_extn = isa_extn_name.lower() + + target_group.add_option('--enable-%s' % (isa_extn), + help='enable use of %s' % (isa_extn_name), + action='append_const', + const=isa_extn, + dest='enable_isa_extns') + + target_group.add_option('--disable-%s' % (isa_extn), + help=optparse.SUPPRESS_HELP, + action='append_const', + const=isa_extn, + dest='disable_isa_extns') + + build_group = optparse.OptionGroup(parser, 'Build options') + + build_group.add_option('--enable-shared', dest='build_shared_lib', + action='store_true', default=True, + help=optparse.SUPPRESS_HELP) + build_group.add_option('--disable-shared', dest='build_shared_lib', + action='store_false', + help='disable building a shared library') + + build_group.add_option('--enable-asm', dest='asm_ok', + action='store_true', default=True, + help=optparse.SUPPRESS_HELP) + build_group.add_option('--disable-asm', dest='asm_ok', + action='store_false', + help='disallow use of assembler') + + build_group.add_option('--enable-debug', dest='debug_build', + action='store_true', default=False, + help='enable debug build') + build_group.add_option('--disable-debug', dest='debug_build', + action='store_false', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--no-optimizations', dest='no_optimizations', + action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--gen-amalgamation', dest='gen_amalgamation', + default=False, action='store_true', + help='generate amalgamation files') + + build_group.add_option('--via-amalgamation', dest='via_amalgamation', + default=False, action='store_true', + help='build via amalgamation') + + build_group.add_option('--with-tr1-implementation', metavar='WHICH', + dest='with_tr1', default=None, + help='enable TR1 (choices: none, system, boost)') + + build_group.add_option('--with-build-dir', + metavar='DIR', default='', + help='setup the build in DIR') + + build_group.add_option('--makefile-style', metavar='STYLE', default=None, + help='choose a makefile style (unix or nmake)') + + build_group.add_option('--with-local-config', + dest='local_config', metavar='FILE', + help='include the contents of FILE into build.h') + + build_group.add_option('--distribution-info', metavar='STRING', + help='set distribution specific versioning', + default='unspecified') + + build_group.add_option('--with-sphinx', action='store_true', + default=None, + help='Use Sphinx to generate HTML manual') + + build_group.add_option('--without-sphinx', action='store_false', + dest='with_sphinx', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-visibility', action='store_true', + default=None, help=optparse.SUPPRESS_HELP) + + build_group.add_option('--without-visibility', action='store_false', + dest='with_visibility', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-doxygen', action='store_true', + default=False, + help='Use Doxygen to generate HTML API docs') + + build_group.add_option('--without-doxygen', action='store_false', + dest='with_doxygen', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--dumb-gcc', dest='dumb_gcc', + action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--maintainer-mode', dest='maintainer_mode', + action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--dirty-tree', dest='clean_build_tree', + action='store_false', default=True, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--link-method', + default=None, + help=optparse.SUPPRESS_HELP) + + wrapper_group = optparse.OptionGroup(parser, 'Wrapper options') + + wrapper_group.add_option('--with-boost-python', dest='boost_python', + default=False, action='store_true', + help='enable Boost.Python wrapper') + + wrapper_group.add_option('--without-boost-python', + dest='boost_python', + action='store_false', + help=optparse.SUPPRESS_HELP) + + wrapper_group.add_option('--with-python-version', dest='python_version', + metavar='N.M', + default='.'.join(map(str, sys.version_info[0:2])), + help='specify Python to build against (eg %default)') + + mods_group = optparse.OptionGroup(parser, 'Module selection') + + mods_group.add_option('--enable-modules', dest='enabled_modules', + metavar='MODS', action='append', + help='enable specific modules') + mods_group.add_option('--disable-modules', dest='disabled_modules', + metavar='MODS', action='append', + help='disable specific modules') + mods_group.add_option('--no-autoload', action='store_true', default=False, + help='disable automatic loading') + + for lib in ['OpenSSL', 'GNU MP', 'Bzip2', 'Zlib']: + + mod = lib.lower().replace(' ', '') + + mods_group.add_option('--with-%s' % (mod), + help='add support for using %s' % (lib), + action='append_const', + const=mod, + dest='enabled_modules') + + mods_group.add_option('--without-%s' % (mod), + help=optparse.SUPPRESS_HELP, + action='append_const', + const=mod, + dest='disabled_modules') + + install_group = optparse.OptionGroup(parser, 'Installation options') + + install_group.add_option('--prefix', metavar='DIR', + help='set the base install directory') + install_group.add_option('--docdir', metavar='DIR', + help='set the documentation install directory') + install_group.add_option('--libdir', metavar='DIR', + help='set the library install directory') + install_group.add_option('--includedir', metavar='DIR', + help='set the include file install directory') + + parser.add_option_group(target_group) + parser.add_option_group(build_group) + parser.add_option_group(mods_group) + parser.add_option_group(wrapper_group) + parser.add_option_group(install_group) + + # These exist only for autoconf compatability (requested by zw for mtn) + compat_with_autoconf_options = [ + 'bindir', + 'datadir', + 'datarootdir', + 'dvidir', + 'exec-prefix', + 'htmldir', + 'infodir', + 'libexecdir', + 'localedir', + 'localstatedir', + 'mandir', + 'oldincludedir', + 'pdfdir', + 'psdir', + 'sbindir', + 'sharedstatedir', + 'sysconfdir' + ] + + for opt in compat_with_autoconf_options: + parser.add_option('--' + opt, help=optparse.SUPPRESS_HELP) + + (options, args) = parser.parse_args(args) + + if args != []: + raise Exception('Unhandled option(s): ' + ' '.join(args)) + if options.with_endian != None and \ + options.with_endian not in ['little', 'big']: + raise Exception('Bad value to --with-endian "%s"' % ( + options.with_endian)) + + def parse_multiple_enable(modules): + if modules is None: + return [] + return sorted(set(flatten([s.split(',') for s in modules]))) + + options.enabled_modules = parse_multiple_enable(options.enabled_modules) + options.disabled_modules = parse_multiple_enable(options.disabled_modules) + + options.enable_isa_extns = parse_multiple_enable(options.enable_isa_extns) + options.disable_isa_extns = parse_multiple_enable(options.disable_isa_extns) + + def enabled_or_disabled_isa(isa): + if isa in options.enable_isa_extns: + return True + if isa in options.disable_isa_extns: + return True + return False + + isa_deps = { + 'ssse3': 'sse2', + 'aes-ni': 'sse2' + } + + if 'sse2' in options.disable_isa_extns: + for isa in [k for (k,v) in isa_deps.items() if v == 'sse2']: + # If explicitly enabled, allow it even if a dependency + # violation; trust the user to know what they want + if not enabled_or_disabled_isa(isa): + options.disable_isa_extns.append(isa) + + for isa in options.enable_isa_extns: + if isa in isa_deps: + for dep in isa_deps.get(isa, '').split(','): + if not enabled_or_disabled_isa(dep): + options.enable_isa_extns.append(dep) + + return options + +""" +Generic lexer function for info.txt and src/build-data files +""" +def lex_me_harder(infofile, to_obj, allowed_groups, name_val_pairs): + + # Format as a nameable Python variable + def py_var(group): + return group.replace(':', '_') + + class LexerError(Exception): + def __init__(self, msg, line): + self.msg = msg + self.line = line + + def __str__(self): + return '%s at %s:%d' % (self.msg, infofile, self.line) + + (dirname, basename) = os.path.split(infofile) + + to_obj.lives_in = dirname + if basename == 'info.txt': + (obj_dir,to_obj.basename) = os.path.split(dirname) + if os.access(os.path.join(obj_dir, 'info.txt'), os.R_OK): + to_obj.parent_module = os.path.basename(obj_dir) + else: + to_obj.parent_module = None + else: + to_obj.basename = basename.replace('.txt', '') + + lexer = shlex.shlex(open(infofile), infofile, posix=True) + lexer.wordchars += '|:.<>/,-!+' # handle various funky chars in info.txt + + for group in allowed_groups: + to_obj.__dict__[py_var(group)] = [] + for (key,val) in name_val_pairs.items(): + to_obj.__dict__[key] = val + + def lexed_tokens(): # Convert to an interator + token = lexer.get_token() + while token != None: + yield token + token = lexer.get_token() + + for token in lexed_tokens(): + match = re.match('<(.*)>', token) + + # Check for a grouping + if match is not None: + group = match.group(1) + + if group not in allowed_groups: + raise LexerError('Unknown group "%s"' % (group), + lexer.lineno) + + end_marker = '' + + token = lexer.get_token() + while token != end_marker: + to_obj.__dict__[py_var(group)].append(token) + token = lexer.get_token() + if token is None: + raise LexerError('Group "%s" not terminated' % (group), + lexer.lineno) + + elif token in name_val_pairs.keys(): + next_val = lexer.get_token() + + if type(to_obj.__dict__[token]) is list: + to_obj.__dict__[token].append(next_val) + else: + to_obj.__dict__[token] = next_val + + else: # No match -> error + raise LexerError('Bad token "%s"' % (token), lexer.lineno) + +""" +Convert a lex'ed map (from build-data files) from a list to a dict +""" +def force_to_dict(l): + return dict(zip(l[::3],l[2::3])) + +""" +Represents the information about a particular module +""" +class ModuleInfo(object): + + def __init__(self, infofile): + + lex_me_harder(infofile, self, + ['source', 'header:internal', 'header:public', + 'requires', 'os', 'arch', 'cc', 'libs', + 'comment'], + { + 'load_on': 'auto', + 'define': [], + 'uses_tr1': 'false', + 'need_isa': None, + 'mp_bits': 0 }) + + def extract_files_matching(basedir, suffixes): + for (dirpath, dirnames, filenames) in os.walk(basedir): + if dirpath == basedir: + for filename in filenames: + if filename.startswith('.'): + continue + + for suffix in suffixes: + if filename.endswith(suffix): + yield filename + + if self.source == []: + self.source = list(extract_files_matching(self.lives_in, ['.cpp', '.S'])) + + if self.header_internal == [] and self.header_public == []: + self.header_public = list(extract_files_matching(self.lives_in, ['.h'])) + + # Coerce to more useful types + def convert_lib_list(l): + result = {} + for (targetlist, vallist) in zip(l[::3], l[2::3]): + vals = vallist.split(',') + for target in targetlist.split(','): + result[target] = result.setdefault(target, []) + vals + return result + + self.libs = convert_lib_list(self.libs) + + def add_dir_name(filename): + if filename.count(':') == 0: + return os.path.join(self.lives_in, filename) + + # modules can request to add files of the form + # MODULE_NAME:FILE_NAME to add a file from another module + # For these, assume other module is always in a + # neighboring directory; this is true for all current uses + return os.path.join(os.path.split(self.lives_in)[0], + *filename.split(':')) + + self.source = [add_dir_name(s) for s in self.source] + self.header_internal = [add_dir_name(s) for s in self.header_internal] + self.header_public = [add_dir_name(s) for s in self.header_public] + + self.mp_bits = int(self.mp_bits) + + self.uses_tr1 = (True if self.uses_tr1 == 'yes' else False) + + if self.comment != []: + self.comment = ' '.join(self.comment) + else: + self.comment = None + + def sources(self): + return self.source + + def public_headers(self): + return self.header_public + + def internal_headers(self): + return self.header_internal + + def defines(self): + return ['HAS_' + d for d in self.define] + + def compatible_cpu(self, archinfo, options): + + arch_name = archinfo.basename + cpu_name = options.cpu + + if self.arch != []: + if arch_name not in self.arch and cpu_name not in self.arch: + return False + + if self.need_isa != None: + if self.need_isa in options.disable_isa_extns: + return False # explicitly disabled + + if self.need_isa in options.enable_isa_extns: + return True # explicitly enabled + + # Default to whatever the CPU is supposed to support + return self.need_isa in archinfo.isa_extensions_in(cpu_name) + + return True + + def compatible_os(self, os): + return self.os == [] or os in self.os + + def compatible_compiler(self, cc): + return self.cc == [] or cc in self.cc + + def tr1_ok(self, with_tr1): + if self.uses_tr1: + return with_tr1 in ['boost', 'system'] + else: + return True + + def dependencies(self): + # utils is an implicit dep (contains types, etc) + deps = self.requires + ['utils'] + if self.parent_module != None: + deps.append(self.parent_module) + return deps + + """ + Ensure that all dependencies of this module actually exist, warning + about any that do not + """ + def dependencies_exist(self, modules): + all_deps = [s.split('|') for s in self.dependencies()] + + for missing in [s for s in flatten(all_deps) if s not in modules]: + logging.warn("Module '%s', dep of '%s', does not exist" % ( + missing, self.basename)) + + def __cmp__(self, other): + if self.basename < other.basename: + return -1 + if self.basename == other.basename: + return 0 + return 1 + +class ArchInfo(object): + def __init__(self, infofile): + lex_me_harder(infofile, self, + ['aliases', 'submodels', 'submodel_aliases', 'isa_extn'], + { 'endian': None, + 'family': None, + 'unaligned': 'no' + }) + + def convert_isa_list(input): + isa_info = {} + for line in self.isa_extn: + (isa,cpus) = line.split(':') + for cpu in cpus.split(','): + isa_info.setdefault(cpu, []).append(isa) + return isa_info + + self.isa_extn = convert_isa_list(self.isa_extn) + + self.submodel_aliases = force_to_dict(self.submodel_aliases) + + self.unaligned_ok = (1 if self.unaligned == 'ok' else 0) + + """ + Return ISA extensions specific to this CPU + """ + def isa_extensions_in(self, cpu_type): + return sorted(self.isa_extn.get(cpu_type, []) + + self.isa_extn.get('all', [])) + + """ + Return a list of all submodels for this arch, ordered longest + to shortest + """ + def all_submodels(self): + return sorted([(k,k) for k in self.submodels] + + [k for k in self.submodel_aliases.items()], + key = lambda k: len(k[0]), reverse = True) + + """ + Return CPU-specific defines for build.h + """ + def defines(self, options): + def form_macro(cpu_name): + return cpu_name.upper().replace('.', '').replace('-', '_') + + macros = ['TARGET_ARCH_IS_%s' % + (form_macro(self.basename.upper()))] + + if self.basename != options.cpu: + macros.append('TARGET_CPU_IS_%s' % (form_macro(options.cpu))) + + enabled_isas = set(self.isa_extensions_in(options.cpu) + + options.enable_isa_extns) + disabled_isas = set(options.disable_isa_extns) + + isa_extensions = sorted(enabled_isas - disabled_isas) + + for isa in isa_extensions: + macros.append('TARGET_CPU_HAS_%s' % (form_macro(isa))) + + endian = options.with_endian or self.endian + + if endian != None: + macros.append('TARGET_CPU_IS_%s_ENDIAN' % (endian.upper())) + logging.info('Assuming CPU is %s endian' % (endian)) + + unaligned_ok = options.unaligned_mem + if unaligned_ok is None: + unaligned_ok = self.unaligned_ok + if unaligned_ok: + logging.info('Assuming unaligned memory access works') + + if self.family is not None: + macros.append('TARGET_CPU_IS_%s_FAMILY' % (self.family.upper())) + + macros.append('TARGET_UNALIGNED_MEMORY_ACCESS_OK %d' % (unaligned_ok)) + + return macros + +class CompilerInfo(object): + def __init__(self, infofile): + lex_me_harder(infofile, self, + ['so_link_flags', 'mach_opt', 'mach_abi_linking'], + { 'binary_name': None, + 'macro_name': None, + 'compile_option': '-c ', + 'output_to_option': '-o ', + 'add_include_dir_option': '-I', + 'add_lib_dir_option': '-L', + 'add_lib_option': '-l', + 'lib_opt_flags': '', + 'check_opt_flags': '', + 'debug_flags': '', + 'no_debug_flags': '', + 'shared_flags': '', + 'lang_flags': '', + 'warning_flags': '', + 'maintainer_warning_flags': '', + 'visibility_build_flags': '', + 'visibility_attribute': '', + 'ar_command': None, + 'makefile_style': '', + 'has_tr1': False, + }) + + self.so_link_flags = force_to_dict(self.so_link_flags) + self.mach_abi_linking = force_to_dict(self.mach_abi_linking) + + self.mach_opt_flags = {} + + while self.mach_opt != []: + proc = self.mach_opt.pop(0) + if self.mach_opt.pop(0) != '->': + raise Exception('Parsing err in %s mach_opt' % (self.basename)) + + flags = self.mach_opt.pop(0) + regex = '' + + if len(self.mach_opt) > 0 and \ + (len(self.mach_opt) == 1 or self.mach_opt[1] != '->'): + regex = self.mach_opt.pop(0) + + self.mach_opt_flags[proc] = (flags,regex) + + del self.mach_opt + + """ + Return the shared library build flags, if any + """ + def gen_shared_flags(self, options): + def flag_builder(): + if options.build_shared_lib: + yield self.shared_flags + if options.with_visibility: + yield self.visibility_build_flags + + return ' '.join(list(flag_builder())) + + def gen_visibility_attribute(self, options): + if options.build_shared_lib and options.with_visibility: + return self.visibility_attribute + return '' + + """ + Return the machine specific ABI flags + """ + def mach_abi_link_flags(self, osname, arch, submodel, debug_p): + + def all(): + if debug_p: + return 'all-debug' + return 'all' + + abi_link = set() + for what in [all(), osname, arch, submodel]: + if self.mach_abi_linking.get(what) != None: + abi_link.add(self.mach_abi_linking.get(what)) + + if len(abi_link) == 0: + return '' + return ' ' + ' '.join(abi_link) + + """ + Return the flags for MACH_OPT + """ + def mach_opts(self, arch, submodel): + + def submodel_fixup(tup): + return tup[0].replace('SUBMODEL', submodel.replace(tup[1], '')) + + if submodel == arch: + return '' + + if submodel in self.mach_opt_flags: + return submodel_fixup(self.mach_opt_flags[submodel]) + if arch in self.mach_opt_flags: + return submodel_fixup(self.mach_opt_flags[arch]) + + return '' + + """ + Return the flags for LIB_OPT + """ + def library_opt_flags(self, options): + def gen_flags(): + if options.debug_build: + yield self.debug_flags + + if not options.no_optimizations: + yield self.lib_opt_flags + + if not options.debug_build: + yield self.no_debug_flags + + return (' '.join(gen_flags())).strip() + + """ + Return the command needed to link a shared object + """ + def so_link_command_for(self, osname): + if osname in self.so_link_flags: + return self.so_link_flags[osname] + if 'default' in self.so_link_flags: + return self.so_link_flags['default'] + return '' + + """ + Return defines for build.h + """ + def defines(self, with_tr1): + + def tr1_macro(): + if with_tr1: + if with_tr1 == 'boost': + return ['USE_BOOST_TR1'] + elif with_tr1 == 'system': + return ['USE_STD_TR1'] + elif self.has_tr1: + return ['USE_STD_TR1'] + return [] + + return ['BUILD_COMPILER_IS_' + self.macro_name] + tr1_macro() + +class OsInfo(object): + def __init__(self, infofile): + lex_me_harder(infofile, self, + ['aliases', 'target_features'], + { 'os_type': None, + 'obj_suffix': 'o', + 'so_suffix': 'so', + 'static_suffix': 'a', + 'ar_command': 'ar crs', + 'ar_needs_ranlib': False, + 'install_root': '/usr/local', + 'header_dir': 'include', + 'lib_dir': 'lib', + 'doc_dir': 'share/doc', + 'build_shared': 'yes', + 'install_cmd_data': 'install -m 644', + 'install_cmd_exec': 'install -m 755' + }) + + self.ar_needs_ranlib = bool(self.ar_needs_ranlib) + + self.build_shared = (True if self.build_shared == 'yes' else False) + + def ranlib_command(self): + return ('ranlib' if self.ar_needs_ranlib else 'true') + + def defines(self): + return ['TARGET_OS_IS_%s' % (self.basename.upper())] + \ + ['TARGET_OS_HAS_' + feat.upper() + for feat in sorted(self.target_features)] + +def fixup_proc_name(proc): + proc = proc.lower().replace(' ', '') + for junk in ['(tm)', '(r)']: + proc = proc.replace(junk, '') + return proc + +def canon_processor(archinfo, proc): + proc = fixup_proc_name(proc) + + # First, try to search for an exact match + for ainfo in archinfo.values(): + if ainfo.basename == proc or proc in ainfo.aliases: + return (ainfo.basename, ainfo.basename) + + for (match,submodel) in ainfo.all_submodels(): + if proc == submodel or proc == match: + return (ainfo.basename, submodel) + + logging.debug('Could not find an exact match for CPU "%s"' % (proc)) + + # Now, try searching via regex match + for ainfo in archinfo.values(): + for (match,submodel) in ainfo.all_submodels(): + if re.search(match, proc) != None: + logging.debug('Possible match "%s" with "%s" (%s)' % ( + proc, match, submodel)) + return (ainfo.basename, submodel) + + logging.debug('Known CPU names: ' + ' '.join( + sorted(flatten([[ainfo.basename] + \ + ainfo.aliases + \ + [x for (x,_) in ainfo.all_submodels()] + for ainfo in archinfo.values()])))) + + raise Exception('Unknown or unidentifiable processor "%s"' % (proc)) + +def guess_processor(archinfo): + base_proc = platform.machine() + + if base_proc == '': + raise Exception('Could not determine target CPU; set with --cpu') + + full_proc = fixup_proc_name(platform.processor()) or base_proc + + for ainfo in archinfo.values(): + if ainfo.basename == base_proc or base_proc in ainfo.aliases: + for (match,submodel) in ainfo.all_submodels(): + if re.search(match, full_proc) != None: + return (ainfo.basename, submodel) + + return canon_processor(archinfo, ainfo.basename) + + # No matches, so just use the base proc type + return canon_processor(archinfo, base_proc) + +""" +Read a whole file into memory as a string +""" +def slurp_file(filename): + if filename is None: + return '' + return ''.join(open(filename).readlines()) + +""" +Perform template substitution +""" +def process_template(template_file, variables): + class PercentSignTemplate(string.Template): + delimiter = '%' + + try: + template = PercentSignTemplate(slurp_file(template_file)) + return template.substitute(variables) + except KeyError as e: + raise Exception('Unbound var %s in template %s' % (e, template_file)) + +""" +Create the template variables needed to process the makefile, build.h, etc +""" +def create_template_vars(build_config, options, modules, cc, arch, osinfo): + def make_cpp_macros(macros): + return '\n'.join(['#define BOTAN_' + macro for macro in macros]) + + """ + Figure out what external libraries are needed based on selected modules + """ + def link_to(): + libs = set() + for module in modules: + for (osname,link_to) in module.libs.items(): + if osname == 'all' or osname == osinfo.basename: + libs |= set(link_to) + else: + match = re.match('^all!(.*)', osname) + if match is not None: + exceptions = match.group(1).split(',') + if osinfo.basename not in exceptions: + libs |= set(link_to) + return sorted(libs) + + def objectfile_list(sources, obj_dir): + for src in sources: + (dir,file) = os.path.split(os.path.normpath(src)) + + if dir.startswith('src'): + parts = dir.split(os.sep)[1:] + if file == parts[-1] + '.cpp': + name = '_'.join(dir.split(os.sep)[1:]) + '.cpp' + else: + name = '_'.join(dir.split(os.sep)[1:]) + '_' + file + else: + name = file + + for src_suffix in ['.cpp', '.S']: + name = name.replace(src_suffix, '.' + osinfo.obj_suffix) + + yield os.path.join(obj_dir, name) + + + def choose_mp_bits(): + mp_bits = [mod.mp_bits for mod in modules if mod.mp_bits != 0] + + if mp_bits == []: + return 32 # default + + # Check that settings are consistent across modules + for mp_bit in mp_bits[1:]: + if mp_bit != mp_bits[0]: + raise Exception('Incompatible mp_bits settings found') + + return mp_bits[0] + + """ + Form snippets of makefile for building each source file + """ + def build_commands(sources, obj_dir, flags): + for (obj_file,src) in zip(objectfile_list(sources, obj_dir), sources): + yield '%s: %s\n\t$(CXX) %s%s $(%s_FLAGS) %s$? %s$@\n' % ( + obj_file, src, + cc.add_include_dir_option, + build_config.include_dir, + flags, + cc.compile_option, + cc.output_to_option) + + def makefile_list(items): + items = list(items) # force evaluation so we can slice it + return (' '*16).join([item + ' \\\n' for item in items[:-1]] + + [items[-1]]) + + def prefix_with_build_dir(path): + if options.with_build_dir != None: + return os.path.join(options.with_build_dir, path) + return path + + def warning_flags(normal_flags, + maintainer_flags, + maintainer_mode): + if maintainer_mode and maintainer_flags != '': + return maintainer_flags + return normal_flags + + return { + 'version_major': build_config.version_major, + 'version_minor': build_config.version_minor, + 'version_patch': build_config.version_patch, + 'version_vc_rev': build_config.version_vc_rev, + 'so_abi_rev': build_config.version_so_rev, + 'version': build_config.version_string, + + 'distribution_info': options.distribution_info, + + 'version_datestamp': build_config.version_datestamp, + + 'timestamp': build_config.timestamp(), + 'user': build_config.username(), + 'hostname': build_config.hostname(), + 'command_line': ' '.join(sys.argv), + 'local_config': slurp_file(options.local_config), + 'makefile_style': options.makefile_style or cc.makefile_style, + + 'makefile_path': prefix_with_build_dir('Makefile'), + + 'prefix': options.prefix or osinfo.install_root, + 'libdir': options.libdir or osinfo.lib_dir, + 'includedir': options.includedir or osinfo.header_dir, + 'docdir': options.docdir or osinfo.doc_dir, + + 'build_dir': build_config.build_dir, + 'doc_output_dir': build_config.doc_output_dir, + + 'build_doc_commands': build_config.build_doc_commands, + + 'python_dir': build_config.python_dir, + + 'os': options.os, + 'arch': options.arch, + 'submodel': options.cpu, + + 'mp_bits': choose_mp_bits(), + + 'cc': (options.compiler_binary or cc.binary_name) + + cc.mach_abi_link_flags(options.os, options.arch, + options.cpu, options.debug_build), + + 'lib_opt': cc.library_opt_flags(options), + 'mach_opt': cc.mach_opts(options.arch, options.cpu), + 'check_opt': '' if options.no_optimizations else cc.check_opt_flags, + 'lang_flags': cc.lang_flags + options.extra_flags, + 'warn_flags': warning_flags(cc.warning_flags, + cc.maintainer_warning_flags, + options.maintainer_mode), + + 'shared_flags': cc.gen_shared_flags(options), + 'visibility_attribute': cc.gen_visibility_attribute(options), + + 'so_link': cc.so_link_command_for(osinfo.basename), + + 'link_to': ' '.join([cc.add_lib_option + lib for lib in link_to()]), + + 'module_defines': make_cpp_macros(sorted(flatten([m.defines() for m in modules]))), + + 'target_os_defines': make_cpp_macros(osinfo.defines()), + + 'target_compiler_defines': make_cpp_macros( + cc.defines(options.with_tr1)), + + 'target_cpu_defines': make_cpp_macros(arch.defines(options)), + + 'include_files': makefile_list(build_config.public_headers), + + 'lib_objs': makefile_list( + objectfile_list(build_config.build_sources, + build_config.libobj_dir)), + + 'check_objs': makefile_list( + objectfile_list(build_config.check_sources, + build_config.checkobj_dir)), + + 'lib_build_cmds': '\n'.join( + build_commands(build_config.build_sources, + build_config.libobj_dir, 'LIB')), + + 'check_build_cmds': '\n'.join( + build_commands(build_config.check_sources, + build_config.checkobj_dir, 'CHECK')), + + 'python_obj_dir': build_config.pyobject_dir, + + 'python_objs': makefile_list( + objectfile_list(build_config.python_sources, + build_config.pyobject_dir)), + + 'python_build_cmds': '\n'.join( + build_commands(build_config.python_sources, + build_config.pyobject_dir, 'PYTHON')), + + 'ar_command': cc.ar_command or osinfo.ar_command, + 'ranlib_command': osinfo.ranlib_command(), + 'install_cmd_exec': osinfo.install_cmd_exec, + 'install_cmd_data': osinfo.install_cmd_data, + + 'check_prefix': prefix_with_build_dir(''), + 'lib_prefix': prefix_with_build_dir(''), + + 'static_suffix': osinfo.static_suffix, + 'so_suffix': osinfo.so_suffix, + + 'botan_config': prefix_with_build_dir( + os.path.join(build_config.build_dir, + build_config.config_shell_script())), + + 'botan_pkgconfig': prefix_with_build_dir( + os.path.join(build_config.build_dir, + build_config.pkg_config_file())), + + 'mod_list': '\n'.join(sorted([m.basename for m in modules])), + + 'python_version': options.python_version + } + +""" +Determine which modules to load based on options, target, etc +""" +def choose_modules_to_use(modules, archinfo, options): + + for mod in modules.values(): + mod.dependencies_exist(modules) + + to_load = [] + maybe_dep = [] + not_using_because = {} + + def cannot_use_because(mod, reason): + not_using_because.setdefault(reason, []).append(mod) + + for modname in options.enabled_modules: + if modname not in modules: + logging.warning("Unknown enabled module %s" % (modname)) + + for modname in options.disabled_modules: + if modname not in modules: + logging.warning("Unknown disabled module %s" % (modname)) + + for (modname, module) in modules.items(): + if modname in options.disabled_modules: + cannot_use_because(modname, 'disabled by user') + elif modname in options.enabled_modules: + to_load.append(modname) # trust the user + + elif not module.compatible_os(options.os): + cannot_use_because(modname, 'incompatible OS') + elif not module.compatible_compiler(options.compiler): + cannot_use_because(modname, 'incompatible compiler') + elif not module.compatible_cpu(archinfo, options): + cannot_use_because(modname, 'incompatible CPU') + elif not module.tr1_ok(options.with_tr1): + cannot_use_because(modname, 'missing TR1') + + else: + if module.load_on == 'never': + cannot_use_because(modname, 'disabled as buggy') + elif module.load_on == 'request': + cannot_use_because(modname, 'by request only') + elif module.load_on == 'dep': + maybe_dep.append(modname) + + elif module.load_on == 'always': + to_load.append(modname) + + elif module.load_on == 'asm_ok': + if options.asm_ok: + if options.no_autoload: + maybe_dep.append(modname) + else: + to_load.append(modname) + else: + cannot_use_because(modname, + 'uses assembly and --disable-asm set') + elif module.load_on == 'auto': + if options.no_autoload: + maybe_dep.append(modname) + else: + to_load.append(modname) + else: + logging.warning('Unknown load_on %s in %s' % ( + module.load_on, modname)) + + dependency_failure = True + + while dependency_failure: + dependency_failure = False + for modname in to_load: + for deplist in [s.split('|') for s in modules[modname].dependencies()]: + + dep_met = False + for mod in deplist: + if dep_met is True: + break + + if mod in to_load: + dep_met = True + elif mod in maybe_dep: + maybe_dep.remove(mod) + to_load.append(mod) + dep_met = True + + if dep_met == False: + dependency_failure = True + if modname in to_load: + to_load.remove(modname) + if modname in maybe_dep: + maybe_dep.remove(modname) + cannot_use_because(modname, 'dependency failure') + + for not_a_dep in maybe_dep: + cannot_use_because(not_a_dep, 'loaded only if needed by dependency') + + for reason in sorted(not_using_because.keys()): + disabled_mods = sorted(set([mod for mod in not_using_because[reason]])) + + if disabled_mods != []: + logging.info('Skipping, %s - %s' % ( + reason, ' '.join(disabled_mods))) + + for mod in sorted(to_load): + if mod.startswith('mp_'): + logging.info('Using MP module ' + mod) + if mod.startswith('simd_') and mod != 'simd_engine': + logging.info('Using SIMD module ' + mod) + if modules[mod].comment: + logging.info('%s: %s' % (mod, modules[mod].comment)) + + logging.debug('Loading modules %s', ' '.join(sorted(to_load))) + + return [modules[mod] for mod in to_load] + +""" +Load the info files about modules, targets, etc +""" +def load_info_files(options): + + def find_files_named(desired_name, in_path): + for (dirpath, dirnames, filenames) in os.walk(in_path): + if desired_name in filenames: + yield os.path.join(dirpath, desired_name) + + modules = dict([(mod.basename, mod) for mod in + [ModuleInfo(info) for info in + find_files_named('info.txt', options.src_dir)]]) + + def list_files_in_build_data(subdir): + for (dirpath, dirnames, filenames) in \ + os.walk(os.path.join(options.build_data, subdir)): + for filename in filenames: + if filename.endswith('.txt'): + yield os.path.join(dirpath, filename) + + def form_name(filepath): + return os.path.basename(filepath).replace('.txt', '') + + archinfo = dict([(form_name(info), ArchInfo(info)) + for info in list_files_in_build_data('arch')]) + + osinfo = dict([(form_name(info), OsInfo(info)) + for info in list_files_in_build_data('os')]) + + ccinfo = dict([(form_name(info), CompilerInfo(info)) + for info in list_files_in_build_data('cc')]) + + def info_file_load_report(type, num): + if num > 0: + logging.debug('Loaded %d %s info files' % (num, type)) + else: + logging.warning('Failed to load any %s info files' % (type)) + + info_file_load_report('CPU', len(archinfo)); + info_file_load_report('OS', len(osinfo)) + info_file_load_report('compiler', len(ccinfo)) + + return (modules, archinfo, ccinfo, osinfo) + +""" +Perform the filesystem operations needed to setup the build +""" +def setup_build(build_config, options, template_vars): + + """ + Choose the link method based on system availablity and user request + """ + def choose_link_method(req_method): + + def useable_methods(): + if 'symlink' in os.__dict__: + yield 'symlink' + if 'link' in os.__dict__: + yield 'hardlink' + yield 'copy' + + for method in useable_methods(): + if req_method is None or req_method == method: + return method + + logging.info('Could not use requested link method %s' % (req_method)) + return 'copy' + + """ + Copy or link the file, depending on what the platform offers + """ + def portable_symlink(filename, target_dir, method): + + if not os.access(filename, os.R_OK): + logging.warning('Missing file %s' % (filename)) + return + + if method == 'symlink': + def count_dirs(dir, accum = 0): + if dir in ['', '/', os.path.curdir]: + return accum + (dir,basename) = os.path.split(dir) + return accum + 1 + count_dirs(dir) + + dirs_up = count_dirs(target_dir) + + source = os.path.join(os.path.join(*[os.path.pardir]*dirs_up), + filename) + + target = os.path.join(target_dir, os.path.basename(filename)) + + os.symlink(source, target) + + elif method == 'hardlink': + os.link(filename, + os.path.join(target_dir, os.path.basename(filename))) + + elif method == 'copy': + shutil.copy(filename, target_dir) + + else: + raise Exception('Unknown link method %s' % (method)) + + def choose_makefile_template(style): + if style == 'nmake': + return 'nmake.in' + elif style == 'unix': + return ('unix_shr.in' if options.build_shared_lib else 'unix.in') + else: + raise Exception('Unknown makefile style "%s"' % (style)) + + # First delete the build tree, if existing + try: + if options.clean_build_tree: + shutil.rmtree(build_config.build_dir) + except OSError as e: + if e.errno != errno.ENOENT: + logging.error('Problem while removing build dir: %s' % (e)) + + for dir in build_config.build_dirs: + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + logging.error('Error while creating "%s": %s' % (dir, e)) + + makefile_template = os.path.join( + options.makefile_dir, + choose_makefile_template(template_vars['makefile_style'])) + + logging.debug('Using makefile template %s' % (makefile_template)) + + templates_to_proc = { + makefile_template: template_vars['makefile_path'] + } + + def templates_to_use(): + yield (options.build_data, 'buildh.in', 'build.h') + yield (options.build_data, 'botan.doxy.in', 'botan.doxy') + + if options.os != 'windows': + yield (options.build_data, 'botan.pc.in', build_config.pkg_config_file()) + yield (options.build_data, 'botan-config.in', build_config.config_shell_script()) + + if options.os == 'windows': + yield (options.build_data, 'innosetup.in', 'botan.iss') + + if options.boost_python: + yield (options.makefile_dir, 'python.in', 'Makefile.python') + + for (template_dir, template, sink) in templates_to_use(): + source = os.path.join(template_dir, template) + if template_dir == options.build_data: + sink = os.path.join(build_config.build_dir, sink) + templates_to_proc[source] = sink + + for (template, sink) in templates_to_proc.items(): + try: + f = open(sink, 'w') + f.write(process_template(template, template_vars)) + finally: + f.close() + + link_method = choose_link_method(options.link_method) + logging.info('Using %s to link files into build directory' % (link_method)) + + def link_headers(header_list, type, dir): + logging.debug('Linking %d %s header files in %s' % ( + len(header_list), type, dir)) + + for header_file in header_list: + try: + portable_symlink(header_file, dir, link_method) + except OSError as e: + if e.errno != errno.EEXIST: + logging.error('Error linking %s into %s: %s' % ( + header_file, dir, e)) + + link_headers(build_config.public_headers, 'public', + build_config.botan_include_dir) + + link_headers(build_config.build_internal_headers, 'internal', + build_config.internal_include_dir) + +""" +Generate Amalgamation +""" +def generate_amalgamation(build_config): + def ending_with_suffix(suffix): + def predicate(val): + return val.endswith(suffix) + return predicate + + def strip_header_goop(header_name, contents): + header_guard = re.compile('^#define BOTAN_.*_H__$') + + while len(contents) > 0: + if header_guard.match(contents[0]): + contents = contents[1:] + break + + contents = contents[1:] + + if len(contents) == 0: + raise Exception("No header guard found in " + header_name) + + while contents[0] == '\n': + contents = contents[1:] + + while contents[-1] == '\n': + contents = contents[0:-1] + if contents[-1] == '#endif\n': + contents = contents[0:-1] + + return contents + + botan_include = re.compile('#include $') + std_include = re.compile('#include <([^/\.]+)>$') + + class Amalgamation_Generator: + def __init__(self, input_list): + + self.included_already = set() + self.all_std_includes = set() + + self.file_contents = {} + for f in sorted(input_list): + contents = strip_header_goop(f, open(f).readlines()) + self.file_contents[os.path.basename(f)] = contents + + self.contents = '' + for name in self.file_contents: + self.contents += ''.join(list(self.header_contents(name))) + + self.header_includes = '' + for std_header in self.all_std_includes: + self.header_includes += '#include <%s>\n' % (std_header) + self.header_includes += '\n' + + def header_contents(self, name): + name = name.replace('internal/', '') + + if name in self.included_already: + return + + self.included_already.add(name) + + if name not in self.file_contents: + return + + for line in self.file_contents[name]: + match = botan_include.search(line) + if match: + for c in self.header_contents(match.group(1)): + yield c + else: + match = std_include.search(line) + + if match and match.group(1) != 'functional': + self.all_std_includes.add(match.group(1)) + else: + yield line + + amalg_basename = 'botan_all' + + header_name = '%s.h' % (amalg_basename) + + botan_h = open(header_name, 'w') + + pub_header_amalag = Amalgamation_Generator(build_config.public_headers) + + amalg_header = """/* +* Botan %s Amalgamation +* (C) 1999-2011 Jack Lloyd and others +* +* Distributed under the terms of the Botan license +*/ +""" % (build_config.version_string) + + botan_h.write(amalg_header) + + botan_h.write(""" +#ifndef BOTAN_AMALGAMATION_H__ +#define BOTAN_AMALGAMATION_H__ + +""") + + botan_h.write(pub_header_amalag.header_includes) + botan_h.write(pub_header_amalag.contents) + botan_h.write("\n#endif\n") + + internal_header_amalag = Amalgamation_Generator( + [s for s in build_config.internal_headers + if s.find('asm_macr_') == -1]) + + botan_cpp = open('%s.cpp' % (amalg_basename), 'w') + + botan_cpp.write(amalg_header) + + botan_cpp.write('\n#include "%s"\n' % (header_name)) + + botan_cpp.write(internal_header_amalag.header_includes) + botan_cpp.write(internal_header_amalag.contents) + + for src in build_config.sources: + if src.endswith('.S'): + continue + + contents = open(src).readlines() + for line in contents: + if botan_include.search(line): + continue + else: + botan_cpp.write(line) + +""" +Test for the existence of a program +""" +def have_program(program): + + def exe_test(path, program): + exe_file = os.path.join(path, program) + + if os.path.exists(exe_file) and os.access(exe_file, os.X_OK): + logging.debug('Found program %s in %s' % (program, path)) + return True + else: + return False + + exe_suffixes = ['', '.exe'] + + for path in os.environ['PATH'].split(os.pathsep): + for suffix in exe_suffixes: + if exe_test(path, program + suffix): + return True + + return False + +""" +Main driver +""" +def main(argv = None): + if argv is None: + argv = sys.argv + + logging.basicConfig(stream = sys.stdout, + format = '%(levelname) 7s: %(message)s') + + options = process_command_line(argv[1:]) + + def log_level(): + if options.verbose: + return logging.DEBUG + if options.quiet: + return logging.WARNING + return logging.INFO + + logging.getLogger().setLevel(log_level()) + + logging.debug('%s invoked with options "%s"' % ( + argv[0], ' '.join(argv[1:]))) + + logging.debug('Platform: OS="%s" machine="%s" proc="%s"' % ( + platform.system(), platform.machine(), platform.processor())) + + if options.os == "java": + raise Exception("Jython detected: need --os and --cpu to set target") + + options.base_dir = os.path.dirname(argv[0]) + options.src_dir = os.path.join(options.base_dir, 'src') + + options.build_data = os.path.join(options.src_dir, 'build-data') + options.makefile_dir = os.path.join(options.build_data, 'makefile') + + (modules, archinfo, ccinfo, osinfo) = load_info_files(options) + + if options.compiler is None: + if options.os == 'windows': + if have_program('g++') and not have_program('cl'): + options.compiler = 'gcc' + else: + options.compiler = 'msvc' + else: + options.compiler = 'gcc' + logging.info('Guessing to use compiler %s (use --cc to set)' % ( + options.compiler)) + + if options.os is None: + options.os = platform.system().lower() + + if re.match('^cygwin_.*', options.os): + logging.debug("Converting '%s' to 'cygwin'", options.os) + options.os = 'cygwin' + + if options.os == 'windows' and options.compiler == 'gcc': + logging.warning('Detected GCC on Windows; use --os=cygwin or --os=mingw?') + + logging.info('Guessing target OS is %s (use --os to set)' % (options.os)) + + if options.compiler not in ccinfo: + raise Exception('Unknown compiler "%s"; available options: %s' % ( + options.compiler, ' '.join(sorted(ccinfo.keys())))) + + if options.os not in osinfo: + + def find_canonical_os_name(os): + for (name, info) in osinfo.items(): + if os in info.aliases: + return name + return os # not found + + options.os = find_canonical_os_name(options.os) + + if options.os not in osinfo: + raise Exception('Unknown OS "%s"; available options: %s' % ( + options.os, ' '.join(sorted(osinfo.keys())))) + + if options.cpu is None: + (options.arch, options.cpu) = guess_processor(archinfo) + logging.info('Guessing target processor is a %s/%s (use --cpu to set)' % ( + options.arch, options.cpu)) + else: + cpu_from_user = options.cpu + (options.arch, options.cpu) = canon_processor(archinfo, options.cpu) + logging.info('Canonicalizized --cpu=%s to %s/%s' % ( + cpu_from_user, options.arch, options.cpu)) + + logging.info('Target is %s-%s-%s-%s' % ( + options.compiler, options.os, options.arch, options.cpu)) + + cc = ccinfo[options.compiler] + + # Kind of a hack... + options.extra_flags = '' + if options.compiler == 'gcc': + + def get_gcc_version(gcc_bin): + try: + gcc_proc = subprocess.Popen( + gcc_bin.split(' ') + ['-dumpversion'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + + (stdout, stderr) = gcc_proc.communicate() + + if gcc_proc.returncode != 0: + logging.warning("GCC returned non-zero result %s" % (stderr)) + return None + + gcc_version = stdout.strip() + + logging.info('Detected gcc version %s' % (gcc_version)) + return gcc_version + except OSError: + logging.warning('Could not execute %s for version check' % (gcc_bin)) + return None + + def is_64bit_arch(arch): + if arch.endswith('64') or arch in ['alpha', 's390x']: + return True + return False + + gcc_version = get_gcc_version(options.compiler_binary or cc.binary_name) + + if gcc_version: + + if not is_64bit_arch(options.arch) and not options.dumb_gcc: + matching_version = '(4\.[01234]\.)|(3\.[34]\.)|(2\.95\.[0-4])' + + if re.search(matching_version, gcc_version): + options.dumb_gcc = True + + versions_without_tr1 = '(4\.0\.)|(3\.[0-4]\.)|(2\.95\.[0-4])' + + if options.with_tr1 == None and \ + re.search(versions_without_tr1, gcc_version): + logging.info('Disabling TR1 support for this gcc, too old') + options.with_tr1 = 'none' + + versions_without_visibility = '(3\.[0-4]\.)|(2\.95\.[0-4])' + if options.with_visibility == None and \ + re.search(versions_without_visibility, gcc_version): + logging.info('Disabling DSO visibility support for this gcc, too old') + options.with_visibility = False + + if options.dumb_gcc is True: + logging.info('Setting -fpermissive to work around gcc bug') + options.extra_flags = ' -fpermissive' + + if options.with_visibility is None: + options.with_visibility = True + + if options.with_tr1 == None: + if cc.has_tr1: + logging.info('Assuming %s has TR1 (use --with-tr1=none to disable)' % ( + options.compiler)) + options.with_tr1 = 'system' + else: + options.with_tr1 = 'none' + + if options.with_sphinx is None: + if have_program('sphinx-build'): + logging.info('Found sphinx-build, will use it ' + + '(use --without-sphinx to disable)') + options.with_sphinx = True + + if options.via_amalgamation: + options.gen_amalgamation = True + + if options.gen_amalgamation: + if options.asm_ok: + logging.info('Disabling assembly code, cannot use in amalgamation') + options.asm_ok = False + + modules_to_use = choose_modules_to_use(modules, + archinfo[options.arch], + options) + + if not osinfo[options.os].build_shared: + if options.build_shared_lib: + logging.info('Disabling shared lib on %s' % (options.os)) + options.build_shared_lib = False + + build_config = BuildConfigurationInformation(options, modules_to_use) + build_config.public_headers.append( + os.path.join(build_config.build_dir, 'build.h')) + + template_vars = create_template_vars(build_config, options, + modules_to_use, + cc, + archinfo[options.arch], + osinfo[options.os]) + + # Performs the I/O + setup_build(build_config, options, template_vars) + + if options.gen_amalgamation: + generate_amalgamation(build_config) + + logging.info('Botan %s build setup is complete' % ( + build_config.version_string)) + +if __name__ == '__main__': + try: + main() + except Exception as e: + logging.error(str(e)) + #import traceback + #traceback.print_exc(file=sys.stderr) + sys.exit(1) + sys.exit(0) diff --git a/client/3rd/QtSsh/src/botan/doc/license.txt b/client/3rd/QtSsh/src/botan/doc/license.txt new file mode 100644 index 00000000..aefcee39 --- /dev/null +++ b/client/3rd/QtSsh/src/botan/doc/license.txt @@ -0,0 +1,49 @@ + +.. _license: +.. highlight:: none + +License +======================================== + +Botan (http://botan.randombit.net/) is distributed under these terms:: + + Copyright (C) 1999-2011 Jack Lloyd + 2001 Peter J Jones + 2004-2007 Justin Karneges + 2004 Vaclav Ovsik + 2005 Matthew Gregan + 2005-2006 Matt Johnston + 2006 Luca Piccarreta + 2007 Yves Jerschow + 2007-2008 FlexSecure GmbH + 2007-2008 Technische Universitat Darmstadt + 2007-2008 Falko Strenzke + 2007-2008 Martin Doering + 2007 Manuel Hartl + 2007 Christoph Ludwig + 2007 Patrick Sona + 2010 Olivier de Gaalon + 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 AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. diff --git a/client/3rd/QtSsh/src/botan/readme.txt b/client/3rd/QtSsh/src/botan/readme.txt new file mode 100644 index 00000000..e7b052a0 --- /dev/null +++ b/client/3rd/QtSsh/src/botan/readme.txt @@ -0,0 +1,15 @@ +Botan 1.10.2, 2012-06-17 +http://botan.randombit.net/ + +Botan is a C++ class library for performing a wide variety of +cryptographic operations. It is released under the 2 clause BSD +license; see doc/license.txt for the specifics. You can file bugs in +Bugzilla (http://bugs.randombit.net/) or by sending a report to the +botan-devel mailing list. More information about the mailing list is +at http://lists.randombit.net/mailman/listinfo/botan-devel/ + +You can find documentation online at http://botan.randombit.net/ as +well as in the doc directory in the distribution. Several examples can +be found in doc/examples as well. + +Jack Lloyd (lloyd@randombit.net) diff --git a/client/3rd/QtSsh/src/src.pro b/client/3rd/QtSsh/src/src.pro new file mode 100644 index 00000000..84a0ec5a --- /dev/null +++ b/client/3rd/QtSsh/src/src.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS = ssh \ No newline at end of file diff --git a/client/3rd/QtSsh/src/ssh/sftpchannel.cpp b/client/3rd/QtSsh/src/ssh/sftpchannel.cpp new file mode 100644 index 00000000..2e397ea4 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpchannel.cpp @@ -0,0 +1,972 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpchannel.h" +#include "sftpchannel_p.h" + +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +#include +#include + +/*! + \class QSsh::SftpChannel + + \brief The SftpChannel class provides SFTP operations. + + Objects are created via SshConnection::createSftpChannel(). + The channel needs to be initialized with + a call to initialize() and is closed via closeChannel(). After closing + a channel, no more operations are possible. It cannot be re-opened + using initialize(); use SshConnection::createSftpChannel() if you need + a new one. + + After the initialized() signal has been emitted, operations can be started. + All SFTP operations are asynchronous (non-blocking) and can be in-flight + simultaneously (though callers must ensure that concurrently running jobs + are independent of each other, e.g. they must not write to the same file). + Operations are identified by their job id, which is returned by + the respective member function. If the function can right away detect that + the operation cannot succeed, it returns SftpInvalidJob. If an error occurs + later, the finished() signal is emitted for the respective job with a + non-empty error string. + + Note that directory names must not have a trailing slash. +*/ + +namespace QSsh { +namespace Internal { +namespace { + const quint32 ProtocolVersion = 3; + + QString errorMessage(const QString &serverMessage, + const QString &alternativeMessage) + { + return serverMessage.isEmpty() ? alternativeMessage : serverMessage; + } + + QString errorMessage(const SftpStatusResponse &response, + const QString &alternativeMessage) + { + return response.status == SSH_FX_OK ? QString() + : errorMessage(response.errorString, alternativeMessage); + } +} // anonymous namespace +} // namespace Internal + +SftpChannel::SftpChannel(quint32 channelId, + Internal::SshSendFacility &sendFacility) + : d(new Internal::SftpChannelPrivate(channelId, sendFacility, this)) +{ + connect(d, &Internal::SftpChannelPrivate::initialized, + this, &SftpChannel::initialized, Qt::QueuedConnection); + connect(d, &Internal::SftpChannelPrivate::channelError, + this, &SftpChannel::channelError, Qt::QueuedConnection); + connect(d, &Internal::SftpChannelPrivate::dataAvailable, + this, &SftpChannel::dataAvailable, Qt::QueuedConnection); + connect(d, &Internal::SftpChannelPrivate::fileInfoAvailable, + this, &SftpChannel::fileInfoAvailable, Qt::QueuedConnection); + connect(d, &Internal::SftpChannelPrivate::finished, + this, &SftpChannel::finished, Qt::QueuedConnection); + connect(d, &Internal::SftpChannelPrivate::closed, + this, &SftpChannel::closed, Qt::QueuedConnection); +} + +SftpChannel::State SftpChannel::state() const +{ + switch (d->channelState()) { + case Internal::AbstractSshChannel::Inactive: + return Uninitialized; + case Internal::AbstractSshChannel::SessionRequested: + return Initializing; + case Internal::AbstractSshChannel::CloseRequested: + return Closing; + case Internal::AbstractSshChannel::Closed: + return Closed; + case Internal::AbstractSshChannel::SessionEstablished: + return d->m_sftpState == Internal::SftpChannelPrivate::Initialized + ? Initialized : Initializing; + default: + Q_ASSERT(!"Oh no, we forgot to handle a channel state!"); + return Closed; // For the compiler. + } +} + +void SftpChannel::initialize() +{ + d->requestSessionStart(); + d->m_sftpState = Internal::SftpChannelPrivate::SubsystemRequested; +} + +void SftpChannel::closeChannel() +{ + d->closeChannel(); +} + +SftpJobId SftpChannel::statFile(const QString &path) +{ + return d->createJob(Internal::SftpStatFile::Ptr( + new Internal::SftpStatFile(++d->m_nextJobId, path))); +} + +SftpJobId SftpChannel::listDirectory(const QString &path) +{ + return d->createJob(Internal::SftpListDir::Ptr( + new Internal::SftpListDir(++d->m_nextJobId, path))); +} + +SftpJobId SftpChannel::createDirectory(const QString &path) +{ + return d->createJob(Internal::SftpMakeDir::Ptr( + new Internal::SftpMakeDir(++d->m_nextJobId, path))); +} + +SftpJobId SftpChannel::removeDirectory(const QString &path) +{ + return d->createJob(Internal::SftpRmDir::Ptr( + new Internal::SftpRmDir(++d->m_nextJobId, path))); +} + +SftpJobId SftpChannel::removeFile(const QString &path) +{ + return d->createJob(Internal::SftpRm::Ptr( + new Internal::SftpRm(++d->m_nextJobId, path))); +} + +SftpJobId SftpChannel::renameFileOrDirectory(const QString &oldPath, + const QString &newPath) +{ + return d->createJob(Internal::SftpRename::Ptr( + new Internal::SftpRename(++d->m_nextJobId, oldPath, newPath))); +} + +SftpJobId SftpChannel::createLink(const QString &filePath, const QString &target) +{ + return d->createJob(Internal::SftpCreateLink::Ptr( + new Internal::SftpCreateLink(++d->m_nextJobId, filePath, target))); +} + +SftpJobId SftpChannel::createFile(const QString &path, SftpOverwriteMode mode) +{ + return d->createJob(Internal::SftpCreateFile::Ptr( + new Internal::SftpCreateFile(++d->m_nextJobId, path, mode))); +} + +SftpJobId SftpChannel::uploadFile(const QString &localFilePath, + const QString &remoteFilePath, SftpOverwriteMode mode) +{ + QSharedPointer localFile(new QFile(localFilePath)); + if (!localFile->open(QIODevice::ReadOnly)) + return SftpInvalidJob; + return d->createJob(Internal::SftpUploadFile::Ptr( + new Internal::SftpUploadFile(++d->m_nextJobId, remoteFilePath, localFile, mode))); +} + +SftpJobId SftpChannel::downloadFile(const QString &remoteFilePath, + const QString &localFilePath, SftpOverwriteMode mode) +{ + QSharedPointer localFile(new QFile(localFilePath)); + if (mode == SftpSkipExisting && localFile->exists()) + return SftpInvalidJob; + QIODevice::OpenMode openMode = QIODevice::WriteOnly; + if (mode == SftpOverwriteExisting) + openMode |= QIODevice::Truncate; + else if (mode == SftpAppendToExisting) + openMode |= QIODevice::Append; + if (!localFile->open(openMode)) + return SftpInvalidJob; + return d->createJob(Internal::SftpDownload::Ptr( + new Internal::SftpDownload(++d->m_nextJobId, remoteFilePath, localFile))); +} + +SftpJobId SftpChannel::uploadDir(const QString &localDirPath, + const QString &remoteParentDirPath) +{ + if (state() != Initialized) + return SftpInvalidJob; + const QDir localDir(localDirPath); + if (!localDir.exists() || !localDir.isReadable()) + return SftpInvalidJob; + const Internal::SftpUploadDir::Ptr uploadDirOp( + new Internal::SftpUploadDir(++d->m_nextJobId)); + const QString remoteDirPath + = remoteParentDirPath + QLatin1Char('/') + localDir.dirName(); + const Internal::SftpMakeDir::Ptr mkdirOp( + new Internal::SftpMakeDir(++d->m_nextJobId, remoteDirPath, uploadDirOp)); + uploadDirOp->mkdirsInProgress.insert(mkdirOp, + Internal::SftpUploadDir::Dir(localDirPath, remoteDirPath)); + d->createJob(mkdirOp); + return uploadDirOp->jobId; +} + +SftpChannel::~SftpChannel() +{ + delete d; +} + + +namespace Internal { + +SftpChannelPrivate::SftpChannelPrivate(quint32 channelId, + SshSendFacility &sendFacility, SftpChannel *sftp) + : AbstractSshChannel(channelId, sendFacility), + m_nextJobId(0), m_sftpState(Inactive), m_sftp(sftp) +{ +} + +SftpJobId SftpChannelPrivate::createJob(const AbstractSftpOperation::Ptr &job) +{ + if (m_sftp->state() != SftpChannel::Initialized) + return SftpInvalidJob; + m_jobs.insert(job->jobId, job); + sendData(job->initialPacket(m_outgoingPacket).rawData()); + return job->jobId; +} + +void SftpChannelPrivate::handleChannelSuccess() +{ + if (channelState() == CloseRequested) + return; + qCDebug(sshLog, "sftp subsystem initialized"); + sendData(m_outgoingPacket.generateInit(ProtocolVersion).rawData()); + m_sftpState = InitSent; +} + +void SftpChannelPrivate::handleChannelFailure() +{ + if (channelState() == CloseRequested) + return; + + if (m_sftpState != SubsystemRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_FAILURE packet."); + } + emit channelError(tr("Server could not start SFTP subsystem.")); + closeChannel(); +} + +void SftpChannelPrivate::handleChannelDataInternal(const QByteArray &data) +{ + if (channelState() == CloseRequested) + return; + + m_incomingData += data; + m_incomingPacket.consumeData(m_incomingData); + while (m_incomingPacket.isComplete()) { + handleCurrentPacket(); + m_incomingPacket.clear(); + m_incomingPacket.consumeData(m_incomingData); + } +} + +void SftpChannelPrivate::handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data) +{ + qCWarning(sshLog, "Unexpected extended data '%s' of type %d on SFTP channel.", + data.data(), type); +} + +void SftpChannelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) +{ + qCDebug(sshLog, "Remote SFTP service exited with exit code %d", exitStatus.exitStatus); + + if (channelState() == CloseRequested || channelState() == Closed) + return; + + emit channelError(tr("The SFTP server finished unexpectedly with exit code %1.") + .arg(exitStatus.exitStatus)); + + // Note: According to the specs, the server must close the channel after this happens, + // but OpenSSH doesn't do that, so we need to initiate the closing procedure ourselves. + closeChannel(); +} + +void SftpChannelPrivate::handleExitSignal(const SshChannelExitSignal &signal) +{ + emit channelError(tr("The SFTP server crashed: %1.").arg(signal.error)); + closeChannel(); // See above. +} + +void SftpChannelPrivate::handleCurrentPacket() +{ + qCDebug(sshLog, "Handling SFTP packet of type %d", m_incomingPacket.type()); + switch (m_incomingPacket.type()) { + case SSH_FXP_VERSION: + handleServerVersion(); + break; + case SSH_FXP_HANDLE: + handleHandle(); + break; + case SSH_FXP_NAME: + handleName(); + break; + case SSH_FXP_STATUS: + handleStatus(); + break; + case SSH_FXP_DATA: + handleReadData(); + break; + case SSH_FXP_ATTRS: + handleAttrs(); + break; + default: + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", + tr("Unexpected packet of type %1.").arg(m_incomingPacket.type())); + } +} + +void SftpChannelPrivate::handleServerVersion() +{ + checkChannelActive(); + if (m_sftpState != InitSent) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_VERSION packet."); + } + + qCDebug(sshLog, "sftp init received"); + const quint32 serverVersion = m_incomingPacket.extractServerVersion(); + if (serverVersion != ProtocolVersion) { + emit channelError(tr("Protocol version mismatch: Expected %1, got %2") + .arg(serverVersion).arg(ProtocolVersion)); + closeChannel(); + } else { + m_sftpState = Initialized; + emit initialized(); + } +} + +void SftpChannelPrivate::handleHandle() +{ + const SftpHandleResponse &response = m_incomingPacket.asHandleResponse(); + JobMap::Iterator it = lookupJob(response.requestId); + const QSharedPointer job + = it.value().dynamicCast(); + if (job.isNull()) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_HANDLE packet."); + } + if (job->state != AbstractSftpOperationWithHandle::OpenRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_HANDLE packet."); + } + job->remoteHandle = response.handle; + job->state = AbstractSftpOperationWithHandle::Open; + + switch (it.value()->type()) { + case AbstractSftpOperation::ListDir: + handleLsHandle(it); + break; + case AbstractSftpOperation::CreateFile: + handleCreateFileHandle(it); + break; + case AbstractSftpOperation::Download: + handleGetHandle(it); + break; + case AbstractSftpOperation::UploadFile: + handlePutHandle(it); + break; + default: + Q_ASSERT(!"Oh no, I forgot to handle an SFTP operation type!"); + } +} + +void SftpChannelPrivate::handleLsHandle(const JobMap::Iterator &it) +{ + SftpListDir::Ptr op = it.value().staticCast(); + sendData(m_outgoingPacket.generateReadDir(op->remoteHandle, + op->jobId).rawData()); +} + +void SftpChannelPrivate::handleCreateFileHandle(const JobMap::Iterator &it) +{ + SftpCreateFile::Ptr op = it.value().staticCast(); + sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle, + op->jobId).rawData()); +} + +void SftpChannelPrivate::handleGetHandle(const JobMap::Iterator &it) +{ + SftpDownload::Ptr op = it.value().staticCast(); + sendData(m_outgoingPacket.generateFstat(op->remoteHandle, + op->jobId).rawData()); + op->statRequested = true; +} + +void SftpChannelPrivate::handlePutHandle(const JobMap::Iterator &it) +{ + SftpUploadFile::Ptr op = it.value().staticCast(); + if (op->parentJob && op->parentJob->hasError) + sendTransferCloseHandle(op, it.key()); + + // OpenSSH does not implement the RFC's append functionality, so we + // have to emulate it. + if (op->mode == SftpAppendToExisting) { + sendData(m_outgoingPacket.generateFstat(op->remoteHandle, + op->jobId).rawData()); + op->statRequested = true; + } else { + spawnWriteRequests(it); + } +} + +void SftpChannelPrivate::handleStatus() +{ + const SftpStatusResponse &response = m_incomingPacket.asStatusResponse(); + qCDebug(sshLog, "%s: status = %d", Q_FUNC_INFO, response.status); + JobMap::Iterator it = lookupJob(response.requestId); + switch (it.value()->type()) { + case AbstractSftpOperation::ListDir: + handleLsStatus(it, response); + break; + case AbstractSftpOperation::Download: + handleGetStatus(it, response); + break; + case AbstractSftpOperation::UploadFile: + handlePutStatus(it, response); + break; + case AbstractSftpOperation::MakeDir: + handleMkdirStatus(it, response); + break; + case AbstractSftpOperation::StatFile: + case AbstractSftpOperation::RmDir: + case AbstractSftpOperation::Rm: + case AbstractSftpOperation::Rename: + case AbstractSftpOperation::CreateFile: + case AbstractSftpOperation::CreateLink: + handleStatusGeneric(it, response); + break; + } +} + +void SftpChannelPrivate::handleStatusGeneric(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + AbstractSftpOperation::Ptr op = it.value(); + const QString error = errorMessage(response, tr("Unknown error.")); + emit finished(op->jobId, error); + m_jobs.erase(it); +} + +void SftpChannelPrivate::handleMkdirStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + SftpMakeDir::Ptr op = it.value().staticCast(); + QSharedPointer parentJob = op->parentJob; + if (parentJob == SftpUploadDir::Ptr()) { + handleStatusGeneric(it, response); + return; + } + if (parentJob->hasError) { + m_jobs.erase(it); + return; + } + + typedef QMap::Iterator DirIt; + DirIt dirIt = parentJob->mkdirsInProgress.find(op); + Q_ASSERT(dirIt != parentJob->mkdirsInProgress.end()); + const QString &remoteDir = dirIt.value().remoteDir; + if (response.status == SSH_FX_OK) { + emit dataAvailable(parentJob->jobId, + tr("Created remote directory \"%1\".").arg(remoteDir)); + } else if (response.status == SSH_FX_FAILURE) { + emit dataAvailable(parentJob->jobId, + tr("Remote directory \"%1\" already exists.").arg(remoteDir)); + } else { + parentJob->setError(); + emit finished(parentJob->jobId, + tr("Error creating directory \"%1\": %2") + .arg(remoteDir, response.errorString)); + m_jobs.erase(it); + return; + } + + QDir localDir(dirIt.value().localDir); + const QFileInfoList &dirInfos + = localDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + foreach (const QFileInfo &dirInfo, dirInfos) { + const QString remoteSubDir = remoteDir + QLatin1Char('/') + dirInfo.fileName(); + const SftpMakeDir::Ptr mkdirOp( + new SftpMakeDir(++m_nextJobId, remoteSubDir, parentJob)); + parentJob->mkdirsInProgress.insert(mkdirOp, + SftpUploadDir::Dir(dirInfo.absoluteFilePath(), remoteSubDir)); + createJob(mkdirOp); + } + + const QFileInfoList &fileInfos = localDir.entryInfoList(QDir::Files); + foreach (const QFileInfo &fileInfo, fileInfos) { + QSharedPointer localFile(new QFile(fileInfo.absoluteFilePath())); + if (!localFile->open(QIODevice::ReadOnly)) { + parentJob->setError(); + emit finished(parentJob->jobId, + tr("Could not open local file \"%1\": %2") + .arg(fileInfo.absoluteFilePath(), localFile->errorString())); + m_jobs.erase(it); + return; + } + + const QString remoteFilePath = remoteDir + QLatin1Char('/') + fileInfo.fileName(); + SftpUploadFile::Ptr uploadFileOp(new SftpUploadFile(++m_nextJobId, + remoteFilePath, localFile, SftpOverwriteExisting, parentJob)); + createJob(uploadFileOp); + parentJob->uploadsInProgress.append(uploadFileOp); + } + + parentJob->mkdirsInProgress.erase(dirIt); + if (parentJob->mkdirsInProgress.isEmpty() + && parentJob->uploadsInProgress.isEmpty()) + emit finished(parentJob->jobId); + m_jobs.erase(it); +} + +void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + SftpListDir::Ptr op = it.value().staticCast(); + switch (op->state) { + case SftpListDir::OpenRequested: + emit finished(op->jobId, errorMessage(response.errorString, + tr("Remote directory could not be opened for reading."))); + m_jobs.erase(it); + break; + case SftpListDir::Open: + if (response.status != SSH_FX_EOF) + reportRequestError(op, errorMessage(response.errorString, + tr("Failed to list remote directory contents."))); + op->state = SftpListDir::CloseRequested; + sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle, + op->jobId).rawData()); + break; + case SftpListDir::CloseRequested: + if (!op->hasError) { + const QString error = errorMessage(response, + tr("Failed to close remote directory.")); + emit finished(op->jobId, error); + } + m_jobs.erase(it); + break; + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_STATUS packet."); + } +} + +void SftpChannelPrivate::handleGetStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + SftpDownload::Ptr op = it.value().staticCast(); + switch (op->state) { + case SftpDownload::OpenRequested: + emit finished(op->jobId, + errorMessage(response.errorString, + tr("Failed to open remote file for reading."))); + m_jobs.erase(it); + break; + case SftpDownload::Open: + if (op->statRequested) { + reportRequestError(op, errorMessage(response.errorString, + tr("Failed to retrieve information on the remote file ('stat' failed)."))); + sendTransferCloseHandle(op, response.requestId); + } else { + if ((response.status != SSH_FX_EOF || response.requestId != op->eofId) + && !op->hasError) + reportRequestError(op, errorMessage(response.errorString, + tr("Failed to read remote file."))); + finishTransferRequest(it); + } + break; + case SftpDownload::CloseRequested: + Q_ASSERT(op->inFlightCount == 1); + if (!op->hasError) { + if (response.status == SSH_FX_OK) + emit finished(op->jobId); + else + reportRequestError(op, errorMessage(response.errorString, + tr("Failed to close remote file."))); + } + removeTransferRequest(it); + break; + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_STATUS packet."); + } +} + +void SftpChannelPrivate::handlePutStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + SftpUploadFile::Ptr job = it.value().staticCast(); + switch (job->state) { + case SftpUploadFile::OpenRequested: { + bool emitError = false; + if (job->parentJob) { + if (!job->parentJob->hasError) { + job->parentJob->setError(); + emitError = true; + } + } else { + emitError = true; + } + + if (emitError) { + emit finished(job->jobId, + errorMessage(response.errorString, + tr("Failed to open remote file for writing."))); + } + m_jobs.erase(it); + break; + } + case SftpUploadFile::Open: + if (job->hasError || (job->parentJob && job->parentJob->hasError)) { + job->hasError = true; + finishTransferRequest(it); + return; + } + + if (response.status == SSH_FX_OK) { + sendWriteRequest(it); + } else { + if (job->parentJob) + job->parentJob->setError(); + reportRequestError(job, errorMessage(response.errorString, + tr("Failed to write remote file."))); + finishTransferRequest(it); + } + break; + case SftpUploadFile::CloseRequested: + Q_ASSERT(job->inFlightCount == 1); + if (job->hasError || (job->parentJob && job->parentJob->hasError)) { + m_jobs.erase(it); + return; + } + + if (response.status == SSH_FX_OK) { + if (job->parentJob) { + job->parentJob->uploadsInProgress.removeOne(job); + if (job->parentJob->mkdirsInProgress.isEmpty() + && job->parentJob->uploadsInProgress.isEmpty()) + emit finished(job->parentJob->jobId); + } else { + emit finished(job->jobId); + } + } else { + const QString error = errorMessage(response.errorString, + tr("Failed to close remote file.")); + if (job->parentJob) { + job->parentJob->setError(); + emit finished(job->parentJob->jobId, error); + } else { + emit finished(job->jobId, error); + } + } + m_jobs.erase(it); + break; + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_STATUS packet."); + } +} + +void SftpChannelPrivate::handleName() +{ + const SftpNameResponse &response = m_incomingPacket.asNameResponse(); + JobMap::Iterator it = lookupJob(response.requestId); + switch (it.value()->type()) { + case AbstractSftpOperation::ListDir: { + SftpListDir::Ptr op = it.value().staticCast(); + if (op->state != SftpListDir::Open) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_NAME packet."); + } + + QList fileInfoList; + for (int i = 0; i < response.files.count(); ++i) { + const SftpFile &file = response.files.at(i); + + SftpFileInfo fileInfo; + fileInfo.name = file.fileName; + attributesToFileInfo(file.attributes, fileInfo); + fileInfoList << fileInfo; + } + emit fileInfoAvailable(op->jobId, fileInfoList); + sendData(m_outgoingPacket.generateReadDir(op->remoteHandle, + op->jobId).rawData()); + break; + } + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_NAME packet."); + } +} + +void SftpChannelPrivate::handleReadData() +{ + const SftpDataResponse &response = m_incomingPacket.asDataResponse(); + JobMap::Iterator it = lookupJob(response.requestId); + if (it.value()->type() != AbstractSftpOperation::Download) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_DATA packet."); + } + + SftpDownload::Ptr op = it.value().staticCast(); + if (op->hasError) { + finishTransferRequest(it); + return; + } + + if (!op->localFile->seek(op->offsets[response.requestId])) { + reportRequestError(op, op->localFile->errorString()); + finishTransferRequest(it); + return; + } + + if (op->localFile->write(response.data) != response.data.size()) { + reportRequestError(op, op->localFile->errorString()); + finishTransferRequest(it); + return; + } + + if (op->offset >= op->fileSize && op->fileSize != 0) + finishTransferRequest(it); + else + sendReadRequest(op, response.requestId); +} + +void SftpChannelPrivate::handleAttrs() +{ + const SftpAttrsResponse &response = m_incomingPacket.asAttrsResponse(); + JobMap::Iterator it = lookupJob(response.requestId); + + SftpStatFile::Ptr statOp = it.value().dynamicCast(); + if (statOp) { + SftpFileInfo fileInfo; + fileInfo.name = QFileInfo(statOp->path).fileName(); + attributesToFileInfo(response.attrs, fileInfo); + emit fileInfoAvailable(it.key(), QList() << fileInfo); + emit finished(it.key()); + m_jobs.erase(it); + return; + } + + AbstractSftpTransfer::Ptr transfer + = it.value().dynamicCast(); + if (!transfer || transfer->state != AbstractSftpTransfer::Open + || !transfer->statRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_ATTRS packet."); + } + Q_ASSERT(transfer->type() == AbstractSftpOperation::UploadFile + || transfer->type() == AbstractSftpOperation::Download); + + if (transfer->type() == AbstractSftpOperation::Download) { + SftpDownload::Ptr op = transfer.staticCast(); + if (response.attrs.sizePresent) { + op->fileSize = response.attrs.size; + } else { + op->fileSize = 0; + op->eofId = op->jobId; + } + op->statRequested = false; + spawnReadRequests(op); + } else { + SftpUploadFile::Ptr op = transfer.staticCast(); + if (op->parentJob && op->parentJob->hasError) { + op->hasError = true; + sendTransferCloseHandle(op, op->jobId); + return; + } + + if (response.attrs.sizePresent) { + op->offset = response.attrs.size; + spawnWriteRequests(it); + } else { + if (op->parentJob) + op->parentJob->setError(); + reportRequestError(op, tr("Cannot append to remote file: " + "Server does not support the file size attribute.")); + sendTransferCloseHandle(op, op->jobId); + } + } +} + +SftpChannelPrivate::JobMap::Iterator SftpChannelPrivate::lookupJob(SftpJobId id) +{ + JobMap::Iterator it = m_jobs.find(id); + if (it == m_jobs.end()) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid request id in SFTP packet."); + } + return it; +} + +void SftpChannelPrivate::closeHook() +{ + for (JobMap::ConstIterator it = m_jobs.constBegin(); it != m_jobs.constEnd(); ++it) + emit finished(it.key(), tr("SFTP channel closed unexpectedly.")); + m_jobs.clear(); + m_incomingData.clear(); + m_incomingPacket.clear(); + emit closed(); +} + +void SftpChannelPrivate::handleOpenSuccessInternal() +{ + qCDebug(sshLog, "SFTP session started"); + m_sendFacility.sendSftpPacket(remoteChannel()); + m_sftpState = SubsystemRequested; +} + +void SftpChannelPrivate::handleOpenFailureInternal(const QString &reason) +{ + if (channelState() != SessionRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet."); + } + emit channelError(tr("Server could not start session: %1").arg(reason)); +} + +void SftpChannelPrivate::sendReadRequest(const SftpDownload::Ptr &job, + quint32 requestId) +{ + Q_ASSERT(job->eofId == SftpInvalidJob); + sendData(m_outgoingPacket.generateReadFile(job->remoteHandle, job->offset, + AbstractSftpPacket::MaxDataSize, requestId).rawData()); + job->offsets[requestId] = job->offset; + job->offset += AbstractSftpPacket::MaxDataSize; + if (job->offset >= job->fileSize) + job->eofId = requestId; +} + +void SftpChannelPrivate::reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job, + const QString &error) +{ + emit finished(job->jobId, error); + job->hasError = true; +} + +void SftpChannelPrivate::finishTransferRequest(const JobMap::Iterator &it) +{ + AbstractSftpTransfer::Ptr job = it.value().staticCast(); + if (job->inFlightCount == 1) + sendTransferCloseHandle(job, it.key()); + else + removeTransferRequest(it); +} + +void SftpChannelPrivate::sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job, + quint32 requestId) +{ + sendData(m_outgoingPacket.generateCloseHandle(job->remoteHandle, + requestId).rawData()); + job->state = SftpDownload::CloseRequested; +} + +void SftpChannelPrivate::attributesToFileInfo(const SftpFileAttributes &attributes, + SftpFileInfo &fileInfo) const +{ + if (attributes.sizePresent) { + fileInfo.sizeValid = true; + fileInfo.size = attributes.size; + } + if (attributes.permissionsPresent) { + if (attributes.permissions & 0x8000) // S_IFREG + fileInfo.type = FileTypeRegular; + else if (attributes.permissions & 0x4000) // S_IFDIR + fileInfo.type = FileTypeDirectory; + else + fileInfo.type = FileTypeOther; + fileInfo.permissionsValid = true; + fileInfo.permissions = 0; + if (attributes.permissions & 00001) // S_IXOTH + fileInfo.permissions |= QFile::ExeOther; + if (attributes.permissions & 00002) // S_IWOTH + fileInfo.permissions |= QFile::WriteOther; + if (attributes.permissions & 00004) // S_IROTH + fileInfo.permissions |= QFile::ReadOther; + if (attributes.permissions & 00010) // S_IXGRP + fileInfo.permissions |= QFile::ExeGroup; + if (attributes.permissions & 00020) // S_IWGRP + fileInfo.permissions |= QFile::WriteGroup; + if (attributes.permissions & 00040) // S_IRGRP + fileInfo.permissions |= QFile::ReadGroup; + if (attributes.permissions & 00100) // S_IXUSR + fileInfo.permissions |= QFile::ExeUser | QFile::ExeOwner; + if (attributes.permissions & 00200) // S_IWUSR + fileInfo.permissions |= QFile::WriteUser | QFile::WriteOwner; + if (attributes.permissions & 00400) // S_IRUSR + fileInfo.permissions |= QFile::ReadUser | QFile::ReadOwner; + } +} + +void SftpChannelPrivate::removeTransferRequest(const JobMap::Iterator &it) +{ + --it.value().staticCast()->inFlightCount; + m_jobs.erase(it); +} + +void SftpChannelPrivate::sendWriteRequest(const JobMap::Iterator &it) +{ + SftpUploadFile::Ptr job = it.value().staticCast(); + QByteArray data = job->localFile->read(AbstractSftpPacket::MaxDataSize); + if (job->localFile->error() != QFile::NoError) { + if (job->parentJob) + job->parentJob->setError(); + reportRequestError(job, tr("Error reading local file: %1") + .arg(job->localFile->errorString())); + finishTransferRequest(it); + } else if (data.isEmpty()) { + finishTransferRequest(it); + } else { + sendData(m_outgoingPacket.generateWriteFile(job->remoteHandle, + job->offset, data, it.key()).rawData()); + job->offset += AbstractSftpPacket::MaxDataSize; + } +} + +void SftpChannelPrivate::spawnWriteRequests(const JobMap::Iterator &it) +{ + SftpUploadFile::Ptr op = it.value().staticCast(); + op->calculateInFlightCount(AbstractSftpPacket::MaxDataSize); + sendWriteRequest(it); + for (int i = 1; !op->hasError && i < op->inFlightCount; ++i) + sendWriteRequest(m_jobs.insert(++m_nextJobId, op)); +} + +void SftpChannelPrivate::spawnReadRequests(const SftpDownload::Ptr &job) +{ + job->calculateInFlightCount(AbstractSftpPacket::MaxDataSize); + sendReadRequest(job, job->jobId); + for (int i = 1; i < job->inFlightCount; ++i) { + const quint32 requestId = ++m_nextJobId; + m_jobs.insert(requestId, job); + sendReadRequest(job, requestId); + } +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpchannel.h b/client/3rd/QtSsh/src/ssh/sftpchannel.h new file mode 100644 index 00000000..78857459 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpchannel.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftpdefs.h" +#include "sftpincomingpacket_p.h" + +#include "ssh_global.h" + +#include +#include +#include +#include + +namespace QSsh { + +namespace Internal { +class SftpChannelPrivate; +class SshChannelManager; +class SshSendFacility; +} // namespace Internal + +class QSSH_EXPORT SftpChannel : public QObject +{ + Q_OBJECT + + friend class Internal::SftpChannelPrivate; + friend class Internal::SshChannelManager; +public: + typedef QSharedPointer Ptr; + + enum State { Uninitialized, Initializing, Initialized, Closing, Closed }; + State state() const; + + void initialize(); + void closeChannel(); + + SftpJobId statFile(const QString &path); + SftpJobId listDirectory(const QString &dirPath); + SftpJobId createDirectory(const QString &dirPath); + SftpJobId removeDirectory(const QString &dirPath); + SftpJobId removeFile(const QString &filePath); + SftpJobId renameFileOrDirectory(const QString &oldPath, + const QString &newPath); + SftpJobId createFile(const QString &filePath, SftpOverwriteMode mode); + SftpJobId createLink(const QString &filePath, const QString &target); + SftpJobId uploadFile(const QString &localFilePath, + const QString &remoteFilePath, SftpOverwriteMode mode); + SftpJobId downloadFile(const QString &remoteFilePath, + const QString &localFilePath, SftpOverwriteMode mode); + SftpJobId uploadDir(const QString &localDirPath, + const QString &remoteParentDirPath); + + ~SftpChannel(); + +signals: + void initialized(); + void channelError(const QString &reason); + void closed(); + + // error.isEmpty <=> finished successfully + void finished(QSsh::SftpJobId job, const QString &error = QString()); + + // TODO: Also emit for each file copied by uploadDir(). + void dataAvailable(QSsh::SftpJobId job, const QString &data); + + /* + * This signal is emitted as a result of: + * - statFile() (with the list having exactly one element) + * - listDirectory() (potentially more than once) + */ + void fileInfoAvailable(QSsh::SftpJobId job, const QList &fileInfoList); + +private: + SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility); + + Internal::SftpChannelPrivate *d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpchannel_p.h b/client/3rd/QtSsh/src/ssh/sftpchannel_p.h new file mode 100644 index 00000000..6ab1c3a2 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpchannel_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftpdefs.h" +#include "sftpincomingpacket_p.h" +#include "sftpoperation_p.h" +#include "sftpoutgoingpacket_p.h" +#include "sshchannel_p.h" + +#include +#include + +namespace QSsh { +class SftpChannel; +namespace Internal { + +class SftpChannelPrivate : public AbstractSshChannel +{ + Q_OBJECT + friend class QSsh::SftpChannel; +public: + enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized }; + +signals: + void initialized(); + void channelError(const QString &reason); + void closed(); + void finished(QSsh::SftpJobId job, const QString &error = QString()); + void dataAvailable(QSsh::SftpJobId job, const QString &data); + void fileInfoAvailable(QSsh::SftpJobId job, const QList &fileInfoList); + +private: + typedef QMap JobMap; + + SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility, + SftpChannel *sftp); + SftpJobId createJob(const AbstractSftpOperation::Ptr &job); + + virtual void handleChannelSuccess(); + virtual void handleChannelFailure(); + + virtual void handleOpenSuccessInternal(); + virtual void handleOpenFailureInternal(const QString &reason); + virtual void handleChannelDataInternal(const QByteArray &data); + virtual void handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data); + virtual void handleExitStatus(const SshChannelExitStatus &exitStatus); + virtual void handleExitSignal(const SshChannelExitSignal &signal); + + virtual void closeHook(); + + void handleCurrentPacket(); + void handleServerVersion(); + void handleHandle(); + void handleStatus(); + void handleName(); + void handleReadData(); + void handleAttrs(); + + void handleStatusGeneric(const JobMap::Iterator &it, + const SftpStatusResponse &response); + void handleMkdirStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response); + void handleLsStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response); + void handleGetStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response); + void handlePutStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response); + + void handleLsHandle(const JobMap::Iterator &it); + void handleCreateFileHandle(const JobMap::Iterator &it); + void handleGetHandle(const JobMap::Iterator &it); + void handlePutHandle(const JobMap::Iterator &it); + + void spawnReadRequests(const SftpDownload::Ptr &job); + void spawnWriteRequests(const JobMap::Iterator &it); + void sendReadRequest(const SftpDownload::Ptr &job, quint32 requestId); + void sendWriteRequest(const JobMap::Iterator &it); + void finishTransferRequest(const JobMap::Iterator &it); + void removeTransferRequest(const JobMap::Iterator &it); + void reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job, + const QString &error); + void sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job, + quint32 requestId); + + void attributesToFileInfo(const SftpFileAttributes &attributes, SftpFileInfo &fileInfo) const; + + JobMap::Iterator lookupJob(SftpJobId id); + JobMap m_jobs; + SftpOutgoingPacket m_outgoingPacket; + SftpIncomingPacket m_incomingPacket; + QByteArray m_incomingData; + SftpJobId m_nextJobId; + SftpState m_sftpState; + SftpChannel *m_sftp; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpdefs.cpp b/client/3rd/QtSsh/src/ssh/sftpdefs.cpp new file mode 100644 index 00000000..1964e1e1 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpdefs.cpp @@ -0,0 +1,28 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpdefs.h" + +namespace QSsh { const SftpJobId SftpInvalidJob = 0; } diff --git a/client/3rd/QtSsh/src/ssh/sftpdefs.h b/client/3rd/QtSsh/src/ssh/sftpdefs.h new file mode 100644 index 00000000..71d2d6dd --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpdefs.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include +#include + +namespace QSsh { + +typedef quint32 SftpJobId; +QSSH_EXPORT extern const SftpJobId SftpInvalidJob; + +enum SftpOverwriteMode { + SftpOverwriteExisting, SftpAppendToExisting, SftpSkipExisting +}; + +enum SftpFileType { FileTypeRegular, FileTypeDirectory, FileTypeOther, FileTypeUnknown }; + +class QSSH_EXPORT SftpFileInfo +{ +public: + SftpFileInfo() : type(FileTypeUnknown), sizeValid(false), permissionsValid(false) { } + + QString name; + SftpFileType type; + quint64 size; + QFile::Permissions permissions; + + // The RFC allows an SFTP server not to support any file attributes beyond the name. + bool sizeValid; + bool permissionsValid; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.cpp b/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.cpp new file mode 100644 index 00000000..d3432c55 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpfilesystemmodel.h" + +#include "sftpchannel.h" +#include "sshconnection.h" +#include "sshconnectionmanager.h" + +#include +#include +#include +#include +#include + +namespace QSsh { +namespace Internal { +namespace { + +class SftpDirNode; +class SftpFileNode +{ +public: + SftpFileNode() : parent(0) { } + virtual ~SftpFileNode() { } + + QString path; + SftpFileInfo fileInfo; + SftpDirNode *parent; +}; + +class SftpDirNode : public SftpFileNode +{ +public: + SftpDirNode() : lsState(LsNotYetCalled) { } + ~SftpDirNode() { qDeleteAll(children); } + + enum { LsNotYetCalled, LsRunning, LsFinished } lsState; + QList children; +}; + +typedef QHash DirNodeHash; + +SftpFileNode *indexToFileNode(const QModelIndex &index) +{ + return static_cast(index.internalPointer()); +} + +SftpDirNode *indexToDirNode(const QModelIndex &index) +{ + SftpFileNode * const fileNode = indexToFileNode(index); + QSSH_ASSERT(fileNode); + return dynamic_cast(fileNode); +} + +} // anonymous namespace + +class SftpFileSystemModelPrivate +{ +public: + SshConnection *sshConnection; + SftpChannel::Ptr sftpChannel; + QString rootDirectory; + SftpFileNode *rootNode; + SftpJobId statJobId; + DirNodeHash lsOps; + QList externalJobs; +}; +} // namespace Internal + +using namespace Internal; + +SftpFileSystemModel::SftpFileSystemModel(QObject *parent) + : QAbstractItemModel(parent), d(new SftpFileSystemModelPrivate) +{ + d->sshConnection = 0; + d->rootDirectory = QLatin1Char('/'); + d->rootNode = 0; + d->statJobId = SftpInvalidJob; +} + +SftpFileSystemModel::~SftpFileSystemModel() +{ + shutDown(); + delete d; +} + +void SftpFileSystemModel::setSshConnection(const SshConnectionParameters &sshParams) +{ + QSSH_ASSERT_AND_RETURN(!d->sshConnection); + d->sshConnection = QSsh::acquireConnection(sshParams); + connect(d->sshConnection, &SshConnection::error, + this, &SftpFileSystemModel::handleSshConnectionFailure); + if (d->sshConnection->state() == SshConnection::Connected) { + handleSshConnectionEstablished(); + return; + } + connect(d->sshConnection, &SshConnection::connected, + this, &SftpFileSystemModel::handleSshConnectionEstablished); + if (d->sshConnection->state() == SshConnection::Unconnected) + d->sshConnection->connectToHost(); +} + +void SftpFileSystemModel::setRootDirectory(const QString &path) +{ + beginResetModel(); + d->rootDirectory = path; + delete d->rootNode; + d->rootNode = 0; + d->lsOps.clear(); + d->statJobId = SftpInvalidJob; + endResetModel(); + statRootDirectory(); +} + +QString SftpFileSystemModel::rootDirectory() const +{ + return d->rootDirectory; +} + +SftpJobId SftpFileSystemModel::downloadFile(const QModelIndex &index, const QString &targetFilePath) +{ + QSSH_ASSERT_AND_RETURN_VALUE(d->rootNode, SftpInvalidJob); + const SftpFileNode * const fileNode = indexToFileNode(index); + QSSH_ASSERT_AND_RETURN_VALUE(fileNode, SftpInvalidJob); + QSSH_ASSERT_AND_RETURN_VALUE(fileNode->fileInfo.type == FileTypeRegular, SftpInvalidJob); + const SftpJobId jobId = d->sftpChannel->downloadFile(fileNode->path, targetFilePath, + SftpOverwriteExisting); + if (jobId != SftpInvalidJob) + d->externalJobs << jobId; + return jobId; +} + +int SftpFileSystemModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; // type + name +} + +QVariant SftpFileSystemModel::data(const QModelIndex &index, int role) const +{ + const SftpFileNode * const node = indexToFileNode(index); + if (index.column() == 0 && role == Qt::DecorationRole) { + switch (node->fileInfo.type) { + case FileTypeRegular: + case FileTypeOther: + return QIcon(":/utils/images/unknownfile.png"); + case FileTypeDirectory: + return QIcon(":/utils/images/dir.png"); + case FileTypeUnknown: + return QIcon(":/utils/images/help.png"); // Shows a question mark. + } + } + if (index.column() == 1) { + if (role == Qt::DisplayRole) + return node->fileInfo.name; + if (role == PathRole) + return node->path; + } + return QVariant(); +} + +Qt::ItemFlags SftpFileSystemModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +QVariant SftpFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation != Qt::Horizontal) + return QVariant(); + if (role != Qt::DisplayRole) + return QVariant(); + if (section == 0) + return tr("File Type"); + if (section == 1) + return tr("File Name"); + return QVariant(); +} + +QModelIndex SftpFileSystemModel::index(int row, int column, const QModelIndex &parent) const +{ + if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) + return QModelIndex(); + if (!d->rootNode) + return QModelIndex(); + if (!parent.isValid()) + return createIndex(row, column, d->rootNode); + const SftpDirNode * const parentNode = indexToDirNode(parent); + QSSH_ASSERT_AND_RETURN_VALUE(parentNode, QModelIndex()); + QSSH_ASSERT_AND_RETURN_VALUE(row < parentNode->children.count(), QModelIndex()); + SftpFileNode * const childNode = parentNode->children.at(row); + return createIndex(row, column, childNode); +} + +QModelIndex SftpFileSystemModel::parent(const QModelIndex &child) const +{ + if (!child.isValid()) // Don't assert on this, since the model tester tries it. + return QModelIndex(); + + const SftpFileNode * const childNode = indexToFileNode(child); + QSSH_ASSERT_AND_RETURN_VALUE(childNode, QModelIndex()); + if (childNode == d->rootNode) + return QModelIndex(); + SftpDirNode * const parentNode = childNode->parent; + if (parentNode == d->rootNode) + return createIndex(0, 0, d->rootNode); + const SftpDirNode * const grandParentNode = parentNode->parent; + QSSH_ASSERT_AND_RETURN_VALUE(grandParentNode, QModelIndex()); + return createIndex(grandParentNode->children.indexOf(parentNode), 0, parentNode); +} + +int SftpFileSystemModel::rowCount(const QModelIndex &parent) const +{ + if (!d->rootNode) + return 0; + if (!parent.isValid()) + return 1; + if (parent.column() != 0) + return 0; + SftpDirNode * const dirNode = indexToDirNode(parent); + if (!dirNode) + return 0; + if (dirNode->lsState != SftpDirNode::LsNotYetCalled) + return dirNode->children.count(); + d->lsOps.insert(d->sftpChannel->listDirectory(dirNode->path), dirNode); + dirNode->lsState = SftpDirNode::LsRunning; + return 0; +} + +void SftpFileSystemModel::statRootDirectory() +{ + d->statJobId = d->sftpChannel->statFile(d->rootDirectory); +} + +void SftpFileSystemModel::shutDown() +{ + if (d->sftpChannel) { + disconnect(d->sftpChannel.data(), 0, this, 0); + d->sftpChannel->closeChannel(); + d->sftpChannel.clear(); + } + if (d->sshConnection) { + disconnect(d->sshConnection, 0, this, 0); + QSsh::releaseConnection(d->sshConnection); + d->sshConnection = 0; + } + delete d->rootNode; + d->rootNode = 0; +} + +void SftpFileSystemModel::handleSshConnectionFailure() +{ + emit connectionError(d->sshConnection->errorString()); + beginResetModel(); + shutDown(); + endResetModel(); +} + +void SftpFileSystemModel::handleSftpChannelInitialized() +{ + connect(d->sftpChannel.data(), + &SftpChannel::fileInfoAvailable, + this, &SftpFileSystemModel::handleFileInfo); + connect(d->sftpChannel.data(), &SftpChannel::finished, + this, &SftpFileSystemModel::handleSftpJobFinished); + statRootDirectory(); +} + +void SftpFileSystemModel::handleSshConnectionEstablished() +{ + d->sftpChannel = d->sshConnection->createSftpChannel(); + connect(d->sftpChannel.data(), &SftpChannel::initialized, + this, &SftpFileSystemModel::handleSftpChannelInitialized); + connect(d->sftpChannel.data(), &SftpChannel::channelError, + this, &SftpFileSystemModel::handleSftpChannelError); + d->sftpChannel->initialize(); +} + +void SftpFileSystemModel::handleSftpChannelError(const QString &reason) +{ + emit connectionError(reason); + beginResetModel(); + shutDown(); + endResetModel(); +} + +void SftpFileSystemModel::handleFileInfo(SftpJobId jobId, const QList &fileInfoList) +{ + if (jobId == d->statJobId) { + QSSH_ASSERT_AND_RETURN(!d->rootNode); + beginInsertRows(QModelIndex(), 0, 0); + d->rootNode = new SftpDirNode; + d->rootNode->path = d->rootDirectory; + d->rootNode->fileInfo = fileInfoList.first(); + d->rootNode->fileInfo.name = d->rootDirectory == QLatin1String("/") + ? d->rootDirectory : QFileInfo(d->rootDirectory).fileName(); + endInsertRows(); + return; + } + SftpDirNode * const parentNode = d->lsOps.value(jobId); + QSSH_ASSERT_AND_RETURN(parentNode); + QList filteredList; + foreach (const SftpFileInfo &fi, fileInfoList) { + if (fi.name != QLatin1String(".") && fi.name != QLatin1String("..")) + filteredList << fi; + } + if (filteredList.isEmpty()) + return; + + // In theory beginInsertRows() should suffice, but that fails to have an effect + // if rowCount() returned 0 earlier. + emit layoutAboutToBeChanged(); + + foreach (const SftpFileInfo &fileInfo, filteredList) { + SftpFileNode *childNode; + if (fileInfo.type == FileTypeDirectory) + childNode = new SftpDirNode; + else + childNode = new SftpFileNode; + childNode->path = parentNode->path; + if (!childNode->path.endsWith(QLatin1Char('/'))) + childNode->path += QLatin1Char('/'); + childNode->path += fileInfo.name; + childNode->fileInfo = fileInfo; + childNode->parent = parentNode; + parentNode->children << childNode; + } + emit layoutChanged(); // Should be endInsertRows(), see above. +} + +void SftpFileSystemModel::handleSftpJobFinished(SftpJobId jobId, const QString &errorMessage) +{ + if (jobId == d->statJobId) { + d->statJobId = SftpInvalidJob; + if (!errorMessage.isEmpty()) + emit sftpOperationFailed(tr("Error getting \"stat\" info about \"%1\": %2") + .arg(rootDirectory(), errorMessage)); + return; + } + + DirNodeHash::Iterator it = d->lsOps.find(jobId); + if (it != d->lsOps.end()) { + QSSH_ASSERT(it.value()->lsState == SftpDirNode::LsRunning); + it.value()->lsState = SftpDirNode::LsFinished; + if (!errorMessage.isEmpty()) + emit sftpOperationFailed(tr("Error listing contents of directory \"%1\": %2") + .arg(it.value()->path, errorMessage)); + d->lsOps.erase(it); + return; + } + + const int jobIndex = d->externalJobs.indexOf(jobId); + QSSH_ASSERT_AND_RETURN(jobIndex != -1); + d->externalJobs.removeAt(jobIndex); + emit sftpOperationFinished(jobId, errorMessage); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.h b/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.h new file mode 100644 index 00000000..99f26ee1 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpfilesystemmodel.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftpdefs.h" + +#include "ssh_global.h" + +#include + +namespace QSsh { +class SshConnectionParameters; + +namespace Internal { class SftpFileSystemModelPrivate; } + +// Very simple read-only model. Symbolic links are not followed. +class QSSH_EXPORT SftpFileSystemModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit SftpFileSystemModel(QObject *parent = 0); + ~SftpFileSystemModel(); + + /* + * Once this is called, an SFTP connection is established and the model is populated. + * The effect of additional calls is undefined. + */ + void setSshConnection(const SshConnectionParameters &sshParams); + + void setRootDirectory(const QString &path); // Default is "/". + QString rootDirectory() const; + + SftpJobId downloadFile(const QModelIndex &index, const QString &targetFilePath); + + // Use this to get the full path of a file or directory. + static const int PathRole = Qt::UserRole; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + +signals: + /* + * E.g. "Permission denied". Note that this can happen without direct user intervention, + * due to e.g. the view calling rowCount() on a non-readable directory. This signal should + * therefore not result in a message box or similar, since it might occur very often. + */ + void sftpOperationFailed(const QString &errorMessage); + + /* + * This error is not recoverable. The model will not have any content after + * the signal has been emitted. + */ + void connectionError(const QString &errorMessage); + + // Success <=> error.isEmpty(). + void sftpOperationFinished(QSsh::SftpJobId, const QString &error); + +private: + void handleSshConnectionEstablished(); + void handleSshConnectionFailure(); + void handleSftpChannelInitialized(); + void handleSftpChannelError(const QString &reason); + void handleFileInfo(QSsh::SftpJobId jobId, const QList &fileInfoList); + void handleSftpJobFinished(QSsh::SftpJobId jobId, const QString &errorMessage); + + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + + void statRootDirectory(); + void shutDown(); + + Internal::SftpFileSystemModelPrivate * const d; +}; + +} // namespace QSsh; diff --git a/client/3rd/QtSsh/src/ssh/sftpincomingpacket.cpp b/client/3rd/QtSsh/src/ssh/sftpincomingpacket.cpp new file mode 100644 index 00000000..4f580a16 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpincomingpacket.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpincomingpacket_p.h" + +#include "sshexception_p.h" +#include "sshlogging_p.h" +#include "sshpacketparser_p.h" + +namespace QSsh { +namespace Internal { + +SftpIncomingPacket::SftpIncomingPacket() : m_length(0) +{ +} + +void SftpIncomingPacket::consumeData(QByteArray &newData) +{ + qCDebug(sshLog, "%s: current data size = %d, new data size = %d", Q_FUNC_INFO, + m_data.size(), newData.size()); + + if (isComplete() || dataSize() + newData.size() < sizeof m_length) + return; + + if (dataSize() < sizeof m_length) { + moveFirstBytes(m_data, newData, sizeof m_length - m_data.size()); + m_length = SshPacketParser::asUint32(m_data, static_cast(0)); + if (m_length < static_cast(TypeOffset + 1) + || m_length > MaxPacketSize) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid length field in SFTP packet."); + } + } + + moveFirstBytes(m_data, newData, + qMin(m_length - dataSize() + 4, newData.size())); +} + +void SftpIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source, + int n) +{ + target.append(source.left(n)); + source.remove(0, n); +} + +bool SftpIncomingPacket::isComplete() const +{ + return m_length == dataSize() - 4; +} + +void SftpIncomingPacket::clear() +{ + m_data.clear(); + m_length = 0; +} + +quint32 SftpIncomingPacket::extractServerVersion() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_VERSION); + try { + return SshPacketParser::asUint32(m_data, TypeOffset + 1); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_VERSION packet."); + } +} + +SftpHandleResponse SftpIncomingPacket::asHandleResponse() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_HANDLE); + try { + SftpHandleResponse response; + quint32 offset = RequestIdOffset; + response.requestId = SshPacketParser::asUint32(m_data, &offset); + response.handle = SshPacketParser::asString(m_data, &offset); + return response; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_HANDLE packet"); + } +} + +SftpStatusResponse SftpIncomingPacket::asStatusResponse() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_STATUS); + try { + SftpStatusResponse response; + quint32 offset = RequestIdOffset; + response.requestId = SshPacketParser::asUint32(m_data, &offset); + response.status = static_cast(SshPacketParser::asUint32(m_data, &offset)); + response.errorString = SshPacketParser::asUserString(m_data, &offset); + response.language = SshPacketParser::asString(m_data, &offset); + return response; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_STATUS packet."); + } +} + +SftpNameResponse SftpIncomingPacket::asNameResponse() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_NAME); + try { + SftpNameResponse response; + quint32 offset = RequestIdOffset; + response.requestId = SshPacketParser::asUint32(m_data, &offset); + const quint32 count = SshPacketParser::asUint32(m_data, &offset); + for (quint32 i = 0; i < count; ++i) + response.files << asFile(offset); + return response; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_NAME packet."); + } +} + +SftpDataResponse SftpIncomingPacket::asDataResponse() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_DATA); + try { + SftpDataResponse response; + quint32 offset = RequestIdOffset; + response.requestId = SshPacketParser::asUint32(m_data, &offset); + response.data = SshPacketParser::asString(m_data, &offset); + return response; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_DATA packet."); + } +} + +SftpAttrsResponse SftpIncomingPacket::asAttrsResponse() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_FXP_ATTRS); + try { + SftpAttrsResponse response; + quint32 offset = RequestIdOffset; + response.requestId = SshPacketParser::asUint32(m_data, &offset); + response.attrs = asFileAttributes(offset); + return response; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_FXP_ATTRS packet."); + } +} + +SftpFile SftpIncomingPacket::asFile(quint32 &offset) const +{ + SftpFile file; + file.fileName + = QString::fromUtf8(SshPacketParser::asString(m_data, &offset)); + file.longName + = QString::fromUtf8(SshPacketParser::asString(m_data, &offset)); + file.attributes = asFileAttributes(offset); + return file; +} + +SftpFileAttributes SftpIncomingPacket::asFileAttributes(quint32 &offset) const +{ + SftpFileAttributes attributes; + const quint32 flags = SshPacketParser::asUint32(m_data, &offset); + attributes.sizePresent = flags & SSH_FILEXFER_ATTR_SIZE; + attributes.timesPresent = flags & SSH_FILEXFER_ATTR_ACMODTIME; + attributes.uidAndGidPresent = flags & SSH_FILEXFER_ATTR_UIDGID; + attributes.permissionsPresent = flags & SSH_FILEXFER_ATTR_PERMISSIONS; + if (attributes.sizePresent) + attributes.size = SshPacketParser::asUint64(m_data, &offset); + if (attributes.uidAndGidPresent) { + attributes.uid = SshPacketParser::asUint32(m_data, &offset); + attributes.gid = SshPacketParser::asUint32(m_data, &offset); + } + if (attributes.permissionsPresent) + attributes.permissions = SshPacketParser::asUint32(m_data, &offset); + if (attributes.timesPresent) { + attributes.atime = SshPacketParser::asUint32(m_data, &offset); + attributes.mtime = SshPacketParser::asUint32(m_data, &offset); + } + if (flags & SSH_FILEXFER_ATTR_EXTENDED) { + const quint32 count = SshPacketParser::asUint32(m_data, &offset); + for (quint32 i = 0; i < count; ++i) { + SshPacketParser::asString(m_data, &offset); + SshPacketParser::asString(m_data, &offset); + } + } + return attributes; +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpincomingpacket_p.h b/client/3rd/QtSsh/src/ssh/sftpincomingpacket_p.h new file mode 100644 index 00000000..fe372e30 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpincomingpacket_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftppacket_p.h" + +namespace QSsh { +namespace Internal { + +struct SftpHandleResponse { + quint32 requestId; + QByteArray handle; +}; + +struct SftpStatusResponse { + quint32 requestId; + SftpStatusCode status; + QString errorString; + QByteArray language; +}; + +struct SftpFileAttributes { + bool sizePresent; + bool timesPresent; + bool uidAndGidPresent; + bool permissionsPresent; + quint64 size; + quint32 uid; + quint32 gid; + quint32 permissions; + quint32 atime; + quint32 mtime; +}; + +struct SftpFile { + QString fileName; + QString longName; // Not present in later RFCs, so we don't expose this to the user. + SftpFileAttributes attributes; +}; + +struct SftpNameResponse { + quint32 requestId; + QList files; +}; + +struct SftpDataResponse { + quint32 requestId; + QByteArray data; +}; + +struct SftpAttrsResponse { + quint32 requestId; + SftpFileAttributes attrs; +}; + +class SftpIncomingPacket : public AbstractSftpPacket +{ +public: + SftpIncomingPacket(); + + void consumeData(QByteArray &data); + void clear(); + bool isComplete() const; + quint32 extractServerVersion() const; + SftpHandleResponse asHandleResponse() const; + SftpStatusResponse asStatusResponse() const; + SftpNameResponse asNameResponse() const; + SftpDataResponse asDataResponse() const; + SftpAttrsResponse asAttrsResponse() const; + +private: + void moveFirstBytes(QByteArray &target, QByteArray &source, int n); + + SftpFileAttributes asFileAttributes(quint32 &offset) const; + SftpFile asFile(quint32 &offset) const; + + quint32 m_length; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpoperation.cpp b/client/3rd/QtSsh/src/ssh/sftpoperation.cpp new file mode 100644 index 00000000..257a8515 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpoperation.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpoperation_p.h" + +#include "sftpoutgoingpacket_p.h" + +#include + +namespace QSsh { +namespace Internal { + +AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId) +{ +} + +AbstractSftpOperation::~AbstractSftpOperation() { } + + +SftpStatFile::SftpStatFile(SftpJobId jobId, const QString &path) + : AbstractSftpOperation(jobId), path(path) +{ +} + +SftpOutgoingPacket &SftpStatFile::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateStat(path, jobId); +} + +SftpMakeDir::SftpMakeDir(SftpJobId jobId, const QString &path, + const SftpUploadDir::Ptr &parentJob) + : AbstractSftpOperation(jobId), parentJob(parentJob), remoteDir(path) +{ +} + +SftpOutgoingPacket &SftpMakeDir::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateMkDir(remoteDir, jobId); +} + + +SftpRmDir::SftpRmDir(SftpJobId id, const QString &path) + : AbstractSftpOperation(id), remoteDir(path) +{ +} + +SftpOutgoingPacket &SftpRmDir::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateRmDir(remoteDir, jobId); +} + + +SftpRm::SftpRm(SftpJobId jobId, const QString &path) + : AbstractSftpOperation(jobId), remoteFile(path) {} + +SftpOutgoingPacket &SftpRm::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateRm(remoteFile, jobId); +} + + +SftpRename::SftpRename(SftpJobId jobId, const QString &oldPath, + const QString &newPath) + : AbstractSftpOperation(jobId), oldPath(oldPath), newPath(newPath) +{ +} + +SftpOutgoingPacket &SftpRename::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateRename(oldPath, newPath, jobId); +} + + +SftpCreateLink::SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target) + : AbstractSftpOperation(jobId), filePath(filePath), target(target) +{ +} + +SftpOutgoingPacket &SftpCreateLink::initialPacket(SftpOutgoingPacket &packet) +{ + return packet.generateCreateLink(filePath, target, jobId); +} + + +AbstractSftpOperationWithHandle::AbstractSftpOperationWithHandle(SftpJobId jobId, + const QString &remotePath) + : AbstractSftpOperation(jobId), + remotePath(remotePath), state(Inactive), hasError(false) +{ +} + +AbstractSftpOperationWithHandle::~AbstractSftpOperationWithHandle() { } + + +SftpListDir::SftpListDir(SftpJobId jobId, const QString &path) + : AbstractSftpOperationWithHandle(jobId, path) +{ +} + +SftpOutgoingPacket &SftpListDir::initialPacket(SftpOutgoingPacket &packet) +{ + state = OpenRequested; + return packet.generateOpenDir(remotePath, jobId); +} + + +SftpCreateFile::SftpCreateFile(SftpJobId jobId, const QString &path, + SftpOverwriteMode mode) + : AbstractSftpOperationWithHandle(jobId, path), mode(mode) +{ +} + +SftpOutgoingPacket & SftpCreateFile::initialPacket(SftpOutgoingPacket &packet) +{ + state = OpenRequested; + return packet.generateOpenFileForWriting(remotePath, mode, + SftpOutgoingPacket::DefaultPermissions, jobId); +} + + +const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough. + +AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile) + : AbstractSftpOperationWithHandle(jobId, remotePath), + localFile(localFile), fileSize(0), offset(0), inFlightCount(0), + statRequested(false) +{ +} + +AbstractSftpTransfer::~AbstractSftpTransfer() {} + +void AbstractSftpTransfer::calculateInFlightCount(quint32 chunkSize) +{ + if (fileSize == 0) { + inFlightCount = 1; + } else { + inFlightCount = fileSize / chunkSize; + if (fileSize % chunkSize) + ++inFlightCount; + if (inFlightCount > MaxInFlightCount) + inFlightCount = MaxInFlightCount; + } +} + + +SftpDownload::SftpDownload(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile) + : AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob) +{ +} + +SftpOutgoingPacket &SftpDownload::initialPacket(SftpOutgoingPacket &packet) +{ + state = OpenRequested; + return packet.generateOpenFileForReading(remotePath, jobId); +} + + +SftpUploadFile::SftpUploadFile(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile, SftpOverwriteMode mode, + const SftpUploadDir::Ptr &parentJob) + : AbstractSftpTransfer(jobId, remotePath, localFile), + parentJob(parentJob), mode(mode) +{ + fileSize = localFile->size(); +} + +SftpOutgoingPacket &SftpUploadFile::initialPacket(SftpOutgoingPacket &packet) +{ + state = OpenRequested; + quint32 permissions = 0; + const QFile::Permissions &qtPermissions = localFile->permissions(); + if (qtPermissions & QFile::ExeOther) + permissions |= 1 << 0; + if (qtPermissions & QFile::WriteOther) + permissions |= 1 << 1; + if (qtPermissions & QFile::ReadOther) + permissions |= 1 << 2; + if (qtPermissions & QFile::ExeGroup) + permissions |= 1<< 3; + if (qtPermissions & QFile::WriteGroup) + permissions |= 1<< 4; + if (qtPermissions & QFile::ReadGroup) + permissions |= 1<< 5; + if (qtPermissions & QFile::ExeOwner) + permissions |= 1<< 6; + if (qtPermissions & QFile::WriteOwner) + permissions |= 1<< 7; + if (qtPermissions & QFile::ReadOwner) + permissions |= 1<< 8; + return packet.generateOpenFileForWriting(remotePath, mode, permissions, jobId); +} + +SftpUploadDir::~SftpUploadDir() {} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpoperation_p.h b/client/3rd/QtSsh/src/ssh/sftpoperation_p.h new file mode 100644 index 00000000..3ee703f6 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpoperation_p.h @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftpdefs.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QFile; +QT_END_NAMESPACE + +namespace QSsh { +namespace Internal { + +class SftpOutgoingPacket; + +struct AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + enum Type { + StatFile, ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile + }; + + AbstractSftpOperation(SftpJobId jobId); + virtual ~AbstractSftpOperation(); + virtual Type type() const = 0; + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet) = 0; + + const SftpJobId jobId; + +private: + AbstractSftpOperation(const AbstractSftpOperation &); + AbstractSftpOperation &operator=(const AbstractSftpOperation &); +}; + +struct SftpUploadDir; + +struct SftpStatFile : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpStatFile(SftpJobId jobId, const QString &path); + virtual Type type() const { return StatFile; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString path; +}; + +struct SftpMakeDir : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpMakeDir(SftpJobId jobId, const QString &path, + const QSharedPointer &parentJob = QSharedPointer()); + virtual Type type() const { return MakeDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QSharedPointer parentJob; + const QString remoteDir; +}; + +struct SftpRmDir : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpRmDir(SftpJobId id, const QString &path); + virtual Type type() const { return RmDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString remoteDir; +}; + +struct SftpRm : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpRm(SftpJobId jobId, const QString &path); + virtual Type type() const { return Rm; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString remoteFile; +}; + +struct SftpRename : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpRename(SftpJobId jobId, const QString &oldPath, const QString &newPath); + virtual Type type() const { return Rename; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString oldPath; + const QString newPath; +}; + +struct SftpCreateLink : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target); + virtual Type type() const { return CreateLink; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString filePath; + const QString target; +}; + + +struct AbstractSftpOperationWithHandle : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + enum State { Inactive, OpenRequested, Open, CloseRequested }; + + AbstractSftpOperationWithHandle(SftpJobId jobId, const QString &remotePath); + ~AbstractSftpOperationWithHandle(); + + const QString remotePath; + QByteArray remoteHandle; + State state; + bool hasError; +}; + + +struct SftpListDir : public AbstractSftpOperationWithHandle +{ + typedef QSharedPointer Ptr; + + SftpListDir(SftpJobId jobId, const QString &path); + virtual Type type() const { return ListDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); +}; + + +struct SftpCreateFile : public AbstractSftpOperationWithHandle +{ + typedef QSharedPointer Ptr; + + SftpCreateFile(SftpJobId jobId, const QString &path, SftpOverwriteMode mode); + virtual Type type() const { return CreateFile; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const SftpOverwriteMode mode; +}; + +struct AbstractSftpTransfer : public AbstractSftpOperationWithHandle +{ + typedef QSharedPointer Ptr; + + AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile); + ~AbstractSftpTransfer(); + void calculateInFlightCount(quint32 chunkSize); + + static const int MaxInFlightCount; + + const QSharedPointer localFile; + quint64 fileSize; + quint64 offset; + int inFlightCount; + bool statRequested; +}; + +struct SftpDownload : public AbstractSftpTransfer +{ + typedef QSharedPointer Ptr; + SftpDownload(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile); + virtual Type type() const { return Download; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + QMap offsets; + SftpJobId eofId; +}; + +struct SftpUploadFile : public AbstractSftpTransfer +{ + typedef QSharedPointer Ptr; + + SftpUploadFile(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile, SftpOverwriteMode mode, + const QSharedPointer &parentJob = QSharedPointer()); + virtual Type type() const { return UploadFile; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QSharedPointer parentJob; + SftpOverwriteMode mode; +}; + +// Composite operation. +struct SftpUploadDir +{ + typedef QSharedPointer Ptr; + + struct Dir { + Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {} + QString localDir; + QString remoteDir; + }; + + SftpUploadDir(SftpJobId jobId) : jobId(jobId), hasError(false) {} + ~SftpUploadDir(); + + void setError() + { + hasError = true; + uploadsInProgress.clear(); + mkdirsInProgress.clear(); + } + + const SftpJobId jobId; + bool hasError; + QList uploadsInProgress; + QMap mkdirsInProgress; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket.cpp b/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket.cpp new file mode 100644 index 00000000..69c3a544 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftpoutgoingpacket_p.h" + +#include "sshlogging_p.h" +#include "sshpacket_p.h" + +#include + +#include + +namespace QSsh { +namespace Internal { + +namespace { + const quint32 DefaultAttributes = 0; + const quint32 SSH_FXF_READ = 0x00000001; + const quint32 SSH_FXF_WRITE = 0x00000002; + const quint32 SSH_FXF_APPEND = 0x00000004; + const quint32 SSH_FXF_CREAT = 0x00000008; + const quint32 SSH_FXF_TRUNC = 0x00000010; + const quint32 SSH_FXF_EXCL = 0x00000020; +} + +SftpOutgoingPacket::SftpOutgoingPacket() +{ +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateInit(quint32 version) +{ + return init(SSH_FXP_INIT, 0).appendInt(version).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateStat(const QString &path, quint32 requestId) +{ + return init(SSH_FXP_LSTAT, requestId).appendString(path).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateOpenDir(const QString &path, + quint32 requestId) +{ + return init(SSH_FXP_OPENDIR, requestId).appendString(path).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateReadDir(const QByteArray &handle, + quint32 requestId) +{ + return init(SSH_FXP_READDIR, requestId).appendString(handle).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateCloseHandle(const QByteArray &handle, + quint32 requestId) +{ + return init(SSH_FXP_CLOSE, requestId).appendString(handle).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateMkDir(const QString &path, + quint32 requestId) +{ + return init(SSH_FXP_MKDIR, requestId).appendString(path) + .appendInt(DefaultAttributes).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateRmDir(const QString &path, + quint32 requestId) +{ + return init(SSH_FXP_RMDIR, requestId).appendString(path).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateRm(const QString &path, + quint32 requestId) +{ + return init(SSH_FXP_REMOVE, requestId).appendString(path).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateRename(const QString &oldPath, + const QString &newPath, quint32 requestId) +{ + return init(SSH_FXP_RENAME, requestId).appendString(oldPath) + .appendString(newPath).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForWriting(const QString &path, + SftpOverwriteMode mode, quint32 permissions, quint32 requestId) +{ + QList attributes; + if (permissions != DefaultPermissions) + attributes << SSH_FILEXFER_ATTR_PERMISSIONS << permissions; + else + attributes << DefaultAttributes; + return generateOpenFile(path, Write, mode, attributes, requestId); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path, + quint32 requestId) +{ + // Note: Overwrite mode is irrelevant and will be ignored. + return generateOpenFile(path, Read, SftpSkipExisting, QList() << DefaultAttributes, + requestId); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateReadFile(const QByteArray &handle, + quint64 offset, quint32 length, quint32 requestId) +{ + return init(SSH_FXP_READ, requestId).appendString(handle).appendInt64(offset) + .appendInt(length).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateFstat(const QByteArray &handle, + quint32 requestId) +{ + return init(SSH_FXP_FSTAT, requestId).appendString(handle).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateWriteFile(const QByteArray &handle, + quint64 offset, const QByteArray &data, quint32 requestId) +{ + return init(SSH_FXP_WRITE, requestId).appendString(handle) + .appendInt64(offset).appendString(data).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateCreateLink(const QString &filePath, + const QString &target, quint32 requestId) +{ + return init(SSH_FXP_SYMLINK, requestId).appendString(filePath).appendString(target).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFile(const QString &path, + OpenType openType, SftpOverwriteMode mode, const QList &attributes, quint32 requestId) +{ + quint32 pFlags = 0; + switch (openType) { + case Read: + pFlags = SSH_FXF_READ; + break; + case Write: + pFlags = SSH_FXF_WRITE | SSH_FXF_CREAT; + switch (mode) { + case SftpOverwriteExisting: pFlags |= SSH_FXF_TRUNC; break; + case SftpAppendToExisting: pFlags |= SSH_FXF_APPEND; break; + case SftpSkipExisting: pFlags |= SSH_FXF_EXCL; break; + } + break; + } + + init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags); + foreach (const quint32 attribute, attributes) + appendInt(attribute); + return finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type, + quint32 requestId) +{ + m_data.resize(TypeOffset + 1); + m_data[TypeOffset] = type; + if (type != SSH_FXP_INIT) { + appendInt(requestId); + qCDebug(sshLog, "Generating SFTP packet of type %d with request id %u", type, requestId); + } + return *this; +} + +SftpOutgoingPacket &SftpOutgoingPacket::appendInt(quint32 val) +{ + m_data.append(AbstractSshPacket::encodeInt(val)); + return *this; +} + +SftpOutgoingPacket &SftpOutgoingPacket::appendInt64(quint64 value) +{ + m_data.append(AbstractSshPacket::encodeInt(value)); + return *this; +} + +SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QString &string) +{ + m_data.append(AbstractSshPacket::encodeString(string.toUtf8())); + return *this; +} + +SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QByteArray &string) +{ + m_data += AbstractSshPacket::encodeString(string); + return *this; +} + +SftpOutgoingPacket &SftpOutgoingPacket::finalize() +{ + AbstractSshPacket::setLengthField(m_data); + return *this; +} + +const quint32 SftpOutgoingPacket::DefaultPermissions = std::numeric_limits::max(); + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket_p.h b/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket_p.h new file mode 100644 index 00000000..0fcc67c1 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftpoutgoingpacket_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sftppacket_p.h" +#include "sftpdefs.h" + +namespace QSsh { +namespace Internal { + +class SftpOutgoingPacket : public AbstractSftpPacket +{ +public: + SftpOutgoingPacket(); + SftpOutgoingPacket &generateInit(quint32 version); + SftpOutgoingPacket &generateStat(const QString &path, quint32 requestId); + SftpOutgoingPacket &generateOpenDir(const QString &path, quint32 requestId); + SftpOutgoingPacket &generateReadDir(const QByteArray &handle, + quint32 requestId); + SftpOutgoingPacket &generateCloseHandle(const QByteArray &handle, + quint32 requestId); + SftpOutgoingPacket &generateMkDir(const QString &path, quint32 requestId); + SftpOutgoingPacket &generateRmDir(const QString &path, quint32 requestId); + SftpOutgoingPacket &generateRm(const QString &path, quint32 requestId); + SftpOutgoingPacket &generateRename(const QString &oldPath, + const QString &newPath, quint32 requestId); + SftpOutgoingPacket &generateOpenFileForWriting(const QString &path, + SftpOverwriteMode mode, quint32 permissions, quint32 requestId); + SftpOutgoingPacket &generateOpenFileForReading(const QString &path, + quint32 requestId); + SftpOutgoingPacket &generateReadFile(const QByteArray &handle, + quint64 offset, quint32 length, quint32 requestId); + SftpOutgoingPacket &generateFstat(const QByteArray &handle, + quint32 requestId); + SftpOutgoingPacket &generateWriteFile(const QByteArray &handle, + quint64 offset, const QByteArray &data, quint32 requestId); + + // Note: OpenSSH's SFTP server has a bug that reverses the filePath and target + // arguments, so this operation is not portable. + SftpOutgoingPacket &generateCreateLink(const QString &filePath, const QString &target, + quint32 requestId); + + static const quint32 DefaultPermissions; + +private: + static QByteArray encodeString(const QString &string); + + enum OpenType { Read, Write }; + SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType, + SftpOverwriteMode mode, const QList &attributes, quint32 requestId); + + SftpOutgoingPacket &init(SftpPacketType type, quint32 requestId); + SftpOutgoingPacket &appendInt(quint32 value); + SftpOutgoingPacket &appendInt64(quint64 value); + SftpOutgoingPacket &appendString(const QString &string); + SftpOutgoingPacket &appendString(const QByteArray &string); + SftpOutgoingPacket &finalize(); +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftppacket.cpp b/client/3rd/QtSsh/src/ssh/sftppacket.cpp new file mode 100644 index 00000000..4efaa35d --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftppacket.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sftppacket_p.h" + +#include "sshpacketparser_p.h" + +namespace QSsh { +namespace Internal { + +const quint32 AbstractSftpPacket::MaxDataSize = 32000; +const quint32 AbstractSftpPacket::MaxPacketSize = 34000; +const int AbstractSftpPacket::TypeOffset = 4; +const int AbstractSftpPacket::RequestIdOffset = TypeOffset + 1; +const int AbstractSftpPacket::PayloadOffset = RequestIdOffset + 4; + +AbstractSftpPacket::AbstractSftpPacket() +{ +} + +quint32 AbstractSftpPacket::requestId() const +{ + return SshPacketParser::asUint32(m_data, RequestIdOffset); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sftppacket_p.h b/client/3rd/QtSsh/src/ssh/sftppacket_p.h new file mode 100644 index 00000000..b99f7b36 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sftppacket_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace QSsh { +namespace Internal { + +enum SftpPacketType { + SSH_FXP_INIT = 1, + SSH_FXP_VERSION = 2, + SSH_FXP_OPEN = 3, + SSH_FXP_CLOSE = 4, + SSH_FXP_READ = 5, + SSH_FXP_WRITE = 6, + SSH_FXP_LSTAT = 7, + SSH_FXP_FSTAT = 8, + SSH_FXP_SETSTAT = 9, + SSH_FXP_FSETSTAT = 10, + SSH_FXP_OPENDIR = 11, + SSH_FXP_READDIR = 12, + SSH_FXP_REMOVE = 13, + SSH_FXP_MKDIR = 14, + SSH_FXP_RMDIR = 15, + SSH_FXP_REALPATH = 16, + SSH_FXP_STAT = 17, + SSH_FXP_RENAME = 18, + SSH_FXP_READLINK = 19, + SSH_FXP_SYMLINK = 20, // Removed from later protocol versions. Try not to use. + + SSH_FXP_STATUS = 101, + SSH_FXP_HANDLE = 102, + SSH_FXP_DATA = 103, + SSH_FXP_NAME = 104, + SSH_FXP_ATTRS = 105, + + SSH_FXP_EXTENDED = 200, + SSH_FXP_EXTENDED_REPLY = 201 +}; + +enum SftpStatusCode { + SSH_FX_OK = 0, + SSH_FX_EOF = 1, + SSH_FX_NO_SUCH_FILE = 2, + SSH_FX_PERMISSION_DENIED = 3, + SSH_FX_FAILURE = 4, + SSH_FX_BAD_MESSAGE = 5, + SSH_FX_NO_CONNECTION = 6, + SSH_FX_CONNECTION_LOST = 7, + SSH_FX_OP_UNSUPPORTED = 8 +}; + +enum SftpAttributeType { + SSH_FILEXFER_ATTR_SIZE = 0x00000001, + SSH_FILEXFER_ATTR_UIDGID = 0x00000002, + SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004, + SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008, + SSH_FILEXFER_ATTR_EXTENDED = 0x80000000 +}; + +class AbstractSftpPacket +{ +public: + AbstractSftpPacket(); + quint32 requestId() const; + const QByteArray &rawData() const { return m_data; } + SftpPacketType type() const { return static_cast(m_data.at(TypeOffset)); } + + static const quint32 MaxDataSize; // "Pure" data size per read/writepacket. + static const quint32 MaxPacketSize; + +protected: + quint32 dataSize() const { return static_cast(m_data.size()); } + + static const int TypeOffset; + static const int RequestIdOffset; + static const int PayloadOffset; + + QByteArray m_data; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/ssh.pri b/client/3rd/QtSsh/src/ssh/ssh.pri new file mode 100644 index 00000000..d92bc7e8 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/ssh.pri @@ -0,0 +1,81 @@ +QT += gui network widgets + +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +SOURCES += $$PWD/sshsendfacility.cpp \ + $$PWD/sshremoteprocess.cpp \ + $$PWD/sshpacketparser.cpp \ + $$PWD/sshpacket.cpp \ + $$PWD/sshoutgoingpacket.cpp \ + $$PWD/sshkeygenerator.cpp \ + $$PWD/sshkeyexchange.cpp \ + $$PWD/sshincomingpacket.cpp \ + $$PWD/sshcryptofacility.cpp \ + $$PWD/sshconnection.cpp \ + $$PWD/sshchannelmanager.cpp \ + $$PWD/sshchannel.cpp \ + $$PWD/sshcapabilities.cpp \ + $$PWD/sftppacket.cpp \ + $$PWD/sftpoutgoingpacket.cpp \ + $$PWD/sftpoperation.cpp \ + $$PWD/sftpincomingpacket.cpp \ + $$PWD/sftpdefs.cpp \ + $$PWD/sftpchannel.cpp \ + $$PWD/sshremoteprocessrunner.cpp \ + $$PWD/sshconnectionmanager.cpp \ + $$PWD/sshkeypasswordretriever.cpp \ + $$PWD/sftpfilesystemmodel.cpp \ + $$PWD/sshkeycreationdialog.cpp \ + $$PWD/sshinit.cpp \ + $$PWD/sshdirecttcpiptunnel.cpp \ + $$PWD/sshlogging.cpp \ + $$PWD/sshhostkeydatabase.cpp \ + $$PWD/sshtcpipforwardserver.cpp \ + $$PWD/sshtcpiptunnel.cpp \ + $$PWD/sshforwardedtcpiptunnel.cpp + +HEADERS += $$PWD/sshsendfacility_p.h \ + $$PWD/sshremoteprocess.h \ + $$PWD/sshremoteprocess_p.h \ + $$PWD/sshpacketparser_p.h \ + $$PWD/sshpacket_p.h \ + $$PWD/sshoutgoingpacket_p.h \ + $$PWD/sshkeygenerator.h \ + $$PWD/sshkeyexchange_p.h \ + $$PWD/sshincomingpacket_p.h \ + $$PWD/sshexception_p.h \ + $$PWD/ssherrors.h \ + $$PWD/sshcryptofacility_p.h \ + $$PWD/sshconnection.h \ + $$PWD/sshconnection_p.h \ + $$PWD/sshchannelmanager_p.h \ + $$PWD/sshchannel_p.h \ + $$PWD/sshcapabilities_p.h \ + $$PWD/sshbotanconversions_p.h \ + $$PWD/sftppacket_p.h \ + $$PWD/sftpoutgoingpacket_p.h \ + $$PWD/sftpoperation_p.h \ + $$PWD/sftpincomingpacket_p.h \ + $$PWD/sftpdefs.h \ + $$PWD/sftpchannel.h \ + $$PWD/sftpchannel_p.h \ + $$PWD/sshremoteprocessrunner.h \ + $$PWD/sshconnectionmanager.h \ + $$PWD/sshpseudoterminal.h \ + $$PWD/sshkeypasswordretriever_p.h \ + $$PWD/sftpfilesystemmodel.h \ + $$PWD/sshkeycreationdialog.h \ + $$PWD/ssh_global.h \ + $$PWD/sshdirecttcpiptunnel_p.h \ + $$PWD/sshinit_p.h \ + $$PWD/sshdirecttcpiptunnel.h \ + $$PWD/sshlogging_p.h \ + $$PWD/sshhostkeydatabase.h \ + $$PWD/sshtcpipforwardserver.h \ + $$PWD/sshtcpipforwardserver_p.h \ + $$PWD/sshtcpiptunnel_p.h \ + $$PWD/sshforwardedtcpiptunnel.h \ + $$PWD/sshforwardedtcpiptunnel_p.h + +FORMS += $$PWD/sshkeycreationdialog.ui diff --git a/client/3rd/QtSsh/src/ssh/ssh.pro b/client/3rd/QtSsh/src/ssh/ssh.pro new file mode 100644 index 00000000..f2019e87 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/ssh.pro @@ -0,0 +1,8 @@ +TARGET = QtSsh + +load(qt_module) + +DEFINES += QTCSSH_LIBRARY + +include($$PWD/ssh.pri) +include($$PWD/../botan/botan.pri) diff --git a/client/3rd/QtSsh/src/ssh/ssh_dependencies.pri b/client/3rd/QtSsh/src/ssh/ssh_dependencies.pri new file mode 100644 index 00000000..ccd896a8 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/ssh_dependencies.pri @@ -0,0 +1 @@ +QTC_LIB_NAME = QtcSsh diff --git a/client/3rd/QtSsh/src/ssh/ssh_global.h b/client/3rd/QtSsh/src/ssh/ssh_global.h new file mode 100644 index 00000000..f2737d1b --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/ssh_global.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +//#if defined(QTCSSH_LIBRARY) +//# define QSSH_EXPORT Q_DECL_EXPORT +//#else +//# define QSSH_EXPORT Q_DECL_IMPORT +//#endif + +#define QSSH_EXPORT + +#define QSSH_PRINT_WARNING qWarning("Soft assert at %s:%d", __FILE__, __LINE__) +#define QSSH_ASSERT(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; } } while (false) +#define QSSH_ASSERT_AND_RETURN(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; return; } } while (false) +#define QSSH_ASSERT_AND_RETURN_VALUE(cond, value) do { if (!(cond)) { QSSH_PRINT_WARNING; return value; } } while (false) diff --git a/client/3rd/QtSsh/src/ssh/sshbotanconversions_p.h b/client/3rd/QtSsh/src/ssh/sshbotanconversions_p.h new file mode 100644 index 00000000..f54ca843 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshbotanconversions_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshcapabilities_p.h" +#include "sshexception_p.h" + +#include + +namespace QSsh { +namespace Internal { + +inline const Botan::byte *convertByteArray(const QByteArray &a) +{ + return reinterpret_cast(a.constData()); +} + +inline Botan::byte *convertByteArray(QByteArray &a) +{ + return reinterpret_cast(a.data()); +} + +inline QByteArray convertByteArray(const Botan::SecureVector &v) +{ + return QByteArray(reinterpret_cast(v.begin()), static_cast(v.size())); +} + +inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName) +{ + if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1) + return "modp/ietf/1024"; + if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1) + return "modp/ietf/2048"; + if (rfcAlgoName == SshCapabilities::EcdhNistp256) + return "secp256r1"; + if (rfcAlgoName == SshCapabilities::EcdhNistp384) + return "secp384r1"; + if (rfcAlgoName == SshCapabilities::EcdhNistp521) + return "secp521r1"; + throw SshClientException(SshInternalError, SSH_TR("Unexpected key exchange algorithm \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); +} + +inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName) +{ + if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc + || rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) { + return "AES-128"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc + || rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) { + return "TripleDES"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) { + return "AES-192"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) { + return "AES-256"; + } + throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); +} + +inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName) +{ + if (rfcAlgoName == SshCapabilities::PubKeyDss) + return "EMSA1(SHA-1)"; + if (rfcAlgoName == SshCapabilities::PubKeyRsa) + return "EMSA3(SHA-1)"; + if (rfcAlgoName == SshCapabilities::PubKeyEcdsa256) + return "EMSA1_BSI(SHA-256)"; + if (rfcAlgoName == SshCapabilities::PubKeyEcdsa384) + return "EMSA1_BSI(SHA-384)"; + if (rfcAlgoName == SshCapabilities::PubKeyEcdsa521) + return "EMSA1_BSI(SHA-512)"; + throw SshClientException(SshInternalError, SSH_TR("Unexpected host key algorithm \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); +} + +inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName) +{ + if (rfcAlgoName == SshCapabilities::HMacSha1) + return "SHA-1"; + if (rfcAlgoName == SshCapabilities::HMacSha256) + return "SHA-256"; + if (rfcAlgoName == SshCapabilities::HMacSha384) + return "SHA-384"; + if (rfcAlgoName == SshCapabilities::HMacSha512) + return "SHA-512"; + throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); +} + +inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName) +{ + if (rfcAlgoName == SshCapabilities::HMacSha1) + return 20; + if (rfcAlgoName == SshCapabilities::HMacSha256) + return 32; + if (rfcAlgoName == SshCapabilities::HMacSha384) + return 48; + if (rfcAlgoName == SshCapabilities::HMacSha512) + return 64; + throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshcapabilities.cpp b/client/3rd/QtSsh/src/ssh/sshcapabilities.cpp new file mode 100644 index 00000000..ac0b4a55 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshcapabilities.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshcapabilities_p.h" + +#include "sshexception_p.h" + +#include +#include + +namespace QSsh { +namespace Internal { + +namespace { + QByteArray listAsByteArray(const QList &list) + { + QByteArray array; + foreach (const QByteArray &elem, list) + array += elem + ','; + if (!array.isEmpty()) + array.remove(array.count() - 1, 1); + return array; + } +} // anonymous namspace + +const QByteArray SshCapabilities::DiffieHellmanGroup1Sha1("diffie-hellman-group1-sha1"); +const QByteArray SshCapabilities::DiffieHellmanGroup14Sha1("diffie-hellman-group14-sha1"); +const QByteArray SshCapabilities::EcdhKexNamePrefix("ecdh-sha2-nistp"); +const QByteArray SshCapabilities::EcdhNistp256 = EcdhKexNamePrefix + "256"; +const QByteArray SshCapabilities::EcdhNistp384 = EcdhKexNamePrefix + "384"; +const QByteArray SshCapabilities::EcdhNistp521 = EcdhKexNamePrefix + "521"; +const QList SshCapabilities::KeyExchangeMethods = QList() + << SshCapabilities::EcdhNistp256 + << SshCapabilities::EcdhNistp384 + << SshCapabilities::EcdhNistp521 + << SshCapabilities::DiffieHellmanGroup1Sha1 + << SshCapabilities::DiffieHellmanGroup14Sha1; + +const QByteArray SshCapabilities::PubKeyDss("ssh-dss"); +const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa"); +const QByteArray SshCapabilities::PubKeyEcdsaPrefix("ecdsa-sha2-nistp"); +const QByteArray SshCapabilities::PubKeyEcdsa256 = SshCapabilities::PubKeyEcdsaPrefix + "256"; +const QByteArray SshCapabilities::PubKeyEcdsa384 = SshCapabilities::PubKeyEcdsaPrefix + "384"; +const QByteArray SshCapabilities::PubKeyEcdsa521 = SshCapabilities::PubKeyEcdsaPrefix + "521"; +const QList SshCapabilities::PublicKeyAlgorithms = QList() + << SshCapabilities::PubKeyEcdsa256 + << SshCapabilities::PubKeyEcdsa384 + << SshCapabilities::PubKeyEcdsa521 + << SshCapabilities::PubKeyRsa + << SshCapabilities::PubKeyDss; + +const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc"); +const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes128Cbc("aes128-cbc"); +const QByteArray SshCapabilities::CryptAlgoAes128Ctr("aes128-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes192Ctr("aes192-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes256Ctr("aes256-ctr"); +const QList SshCapabilities::EncryptionAlgorithms + = QList() << SshCapabilities::CryptAlgoAes256Ctr + << SshCapabilities::CryptAlgoAes192Ctr + << SshCapabilities::CryptAlgoAes128Ctr + << SshCapabilities::CryptAlgo3DesCtr + << SshCapabilities::CryptAlgoAes128Cbc + << SshCapabilities::CryptAlgo3DesCbc; + +const QByteArray SshCapabilities::HMacSha1("hmac-sha1"); +const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96"); +const QByteArray SshCapabilities::HMacSha256("hmac-sha2-256"); +const QByteArray SshCapabilities::HMacSha384("hmac-sha2-384"); +const QByteArray SshCapabilities::HMacSha512("hmac-sha2-512"); +const QList SshCapabilities::MacAlgorithms + = QList() /* << SshCapabilities::HMacSha196 */ + << SshCapabilities::HMacSha256 + << SshCapabilities::HMacSha384 + << SshCapabilities::HMacSha512 + << SshCapabilities::HMacSha1; + +const QList SshCapabilities::CompressionAlgorithms + = QList() << "none"; + +const QByteArray SshCapabilities::SshConnectionService("ssh-connection"); + +QList SshCapabilities::commonCapabilities(const QList &myCapabilities, + const QList &serverCapabilities) +{ + QList capabilities; + foreach (const QByteArray &myCapability, myCapabilities) { + if (serverCapabilities.contains(myCapability)) + capabilities << myCapability; + } + + if (!capabilities.isEmpty()) + return capabilities; + + throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Server and client capabilities do not match.", + QCoreApplication::translate("SshConnection", + "Server and client capabilities don't match. " + "Client list was: %1.\nServer list was %2.") + .arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data())) + .arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).data()))); + +} + +QByteArray SshCapabilities::findBestMatch(const QList &myCapabilities, + const QList &serverCapabilities) +{ + return commonCapabilities(myCapabilities, serverCapabilities).first(); +} + +int SshCapabilities::ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo) +{ + if (ecdsaAlgo == PubKeyEcdsa256) + return 32; + if (ecdsaAlgo == PubKeyEcdsa384) + return 48; + if (ecdsaAlgo == PubKeyEcdsa521) + return 66; + throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"") + .arg(QString::fromLatin1(ecdsaAlgo))); +} + +QByteArray SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes) +{ + if (keyWidthInBytes <= 32) + return PubKeyEcdsa256; + if (keyWidthInBytes <= 48) + return PubKeyEcdsa384; + if (keyWidthInBytes <= 66) + return PubKeyEcdsa521; + throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa key size (%1 bytes)") + .arg(keyWidthInBytes)); +} + +const char *SshCapabilities::oid(const QByteArray &ecdsaAlgo) +{ + if (ecdsaAlgo == PubKeyEcdsa256) + return "secp256r1"; + if (ecdsaAlgo == PubKeyEcdsa384) + return "secp384r1"; + if (ecdsaAlgo == PubKeyEcdsa521) + return "secp521r1"; + throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"") + .arg(QString::fromLatin1(ecdsaAlgo))); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshcapabilities_p.h b/client/3rd/QtSsh/src/ssh/sshcapabilities_p.h new file mode 100644 index 00000000..46341681 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshcapabilities_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QSsh { +namespace Internal { + +class SshCapabilities +{ +public: + static const QByteArray DiffieHellmanGroup1Sha1; + static const QByteArray DiffieHellmanGroup14Sha1; + static const QByteArray EcdhKexNamePrefix; + static const QByteArray EcdhNistp256; + static const QByteArray EcdhNistp384; + static const QByteArray EcdhNistp521; // sic + static const QList KeyExchangeMethods; + + static const QByteArray PubKeyDss; + static const QByteArray PubKeyRsa; + static const QByteArray PubKeyEcdsaPrefix; + static const QByteArray PubKeyEcdsa256; + static const QByteArray PubKeyEcdsa384; + static const QByteArray PubKeyEcdsa521; + static const QList PublicKeyAlgorithms; + + static const QByteArray CryptAlgo3DesCbc; + static const QByteArray CryptAlgo3DesCtr; + static const QByteArray CryptAlgoAes128Cbc; + static const QByteArray CryptAlgoAes128Ctr; + static const QByteArray CryptAlgoAes192Ctr; + static const QByteArray CryptAlgoAes256Ctr; + static const QList EncryptionAlgorithms; + + static const QByteArray HMacSha1; + static const QByteArray HMacSha196; + static const QByteArray HMacSha256; + static const QByteArray HMacSha384; + static const QByteArray HMacSha512; + static const QList MacAlgorithms; + + static const QList CompressionAlgorithms; + + static const QByteArray SshConnectionService; + + static QList commonCapabilities(const QList &myCapabilities, + const QList &serverCapabilities); + static QByteArray findBestMatch(const QList &myCapabilities, + const QList &serverCapabilities); + + static int ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo); + static QByteArray ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes); + static const char *oid(const QByteArray &ecdsaAlgo); +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshchannel.cpp b/client/3rd/QtSsh/src/ssh/sshchannel.cpp new file mode 100644 index 00000000..d48622b3 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshchannel.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshchannel_p.h" + +#include "sshincomingpacket_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +#include + +#include + +namespace QSsh { +namespace Internal { + +// "Payload length" (RFC 4253, 6.1), i.e. minus packet type, channel number +// and length field for string. +const quint32 MinMaxPacketSize = 32768 - sizeof(quint32) - sizeof(quint32) - 1; + +const quint32 NoChannel = 0xffffffffu; + +AbstractSshChannel::AbstractSshChannel(quint32 channelId, + SshSendFacility &sendFacility) + : m_sendFacility(sendFacility), + m_localChannel(channelId), m_remoteChannel(NoChannel), + m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0), + m_state(Inactive) +{ + m_timeoutTimer.setSingleShot(true); + connect(&m_timeoutTimer, &QTimer::timeout, this, &AbstractSshChannel::timeout); +} + +AbstractSshChannel::~AbstractSshChannel() +{ + +} + +void AbstractSshChannel::setChannelState(ChannelState state) +{ + m_state = state; + if (state == Closed) + closeHook(); +} + +void AbstractSshChannel::requestSessionStart() +{ + // Note: We are just being paranoid here about the Botan exceptions, + // which are extremely unlikely to happen, because if there was a problem + // with our cryptography stuff, it would have hit us before, on + // establishing the connection. + try { + m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize()); + setChannelState(SessionRequested); + m_timeoutTimer.start(ReplyTimeout); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + closeChannel(); + } +} + +void AbstractSshChannel::sendData(const QByteArray &data) +{ + try { + m_sendBuffer += data; + flushSendBuffer(); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + closeChannel(); + } +} + +quint32 AbstractSshChannel::initialWindowSize() +{ + return maxPacketSize(); +} + +quint32 AbstractSshChannel::maxPacketSize() +{ + return 16 * 1024 * 1024; +} + +void AbstractSshChannel::handleWindowAdjust(quint32 bytesToAdd) +{ + checkChannelActive(); + + const quint64 newValue = m_remoteWindowSize + bytesToAdd; + if (newValue > 0xffffffffu) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Illegal window size requested."); + } + + m_remoteWindowSize = newValue; + flushSendBuffer(); +} + +void AbstractSshChannel::flushSendBuffer() +{ + while (true) { + const quint32 bytesToSend = qMin(m_remoteMaxPacketSize, + qMin(m_remoteWindowSize, m_sendBuffer.size())); + if (bytesToSend == 0) + break; + const QByteArray &data = m_sendBuffer.left(bytesToSend); + m_sendFacility.sendChannelDataPacket(m_remoteChannel, data); + m_sendBuffer.remove(0, bytesToSend); + m_remoteWindowSize -= bytesToSend; + } +} + +void AbstractSshChannel::handleOpenSuccess(quint32 remoteChannelId, + quint32 remoteWindowSize, quint32 remoteMaxPacketSize) +{ + const ChannelState oldState = m_state; + switch (oldState) { + case CloseRequested: // closeChannel() was called while we were in SessionRequested state + case SessionRequested: + break; // Ok, continue. + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet."); + } + + m_timeoutTimer.stop(); + + if (remoteMaxPacketSize < MinMaxPacketSize) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Maximum packet size too low."); + } + + qCDebug(sshLog, "Channel opened. remote channel id: %u, remote window size: %u, " + "remote max packet size: %u", + remoteChannelId, remoteWindowSize, remoteMaxPacketSize); + m_remoteChannel = remoteChannelId; + m_remoteWindowSize = remoteWindowSize; + m_remoteMaxPacketSize = remoteMaxPacketSize; + setChannelState(SessionEstablished); + if (oldState == CloseRequested) + closeChannel(); + else + handleOpenSuccessInternal(); +} + +void AbstractSshChannel::handleOpenFailure(const QString &reason) +{ + switch (m_state) { + case SessionRequested: + break; // Ok, continue. + case CloseRequested: + return; // Late server reply; we requested a channel close in the meantime. + default: + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet."); + } + + m_timeoutTimer.stop(); + + qCDebug(sshLog, "Channel open request failed for channel %u", m_localChannel); + handleOpenFailureInternal(reason); +} + +void AbstractSshChannel::handleChannelEof() +{ + if (m_state == Inactive || m_state == Closed) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_EOF message."); + } + m_localWindowSize = 0; + emit eof(); +} + +void AbstractSshChannel::handleChannelClose() +{ + qCDebug(sshLog, "Receiving CLOSE for channel %u", m_localChannel); + if (channelState() == Inactive || channelState() == Closed) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_CLOSE message."); + } + closeChannel(); + setChannelState(Closed); +} + +void AbstractSshChannel::handleChannelData(const QByteArray &data) +{ + const int bytesToDeliver = handleChannelOrExtendedChannelData(data); + handleChannelDataInternal(bytesToDeliver == data.size() + ? data : data.left(bytesToDeliver)); +} + +void AbstractSshChannel::handleChannelExtendedData(quint32 type, const QByteArray &data) +{ + const int bytesToDeliver = handleChannelOrExtendedChannelData(data); + handleChannelExtendedDataInternal(type, bytesToDeliver == data.size() + ? data : data.left(bytesToDeliver)); +} + +void AbstractSshChannel::handleChannelRequest(const SshIncomingPacket &packet) +{ + checkChannelActive(); + const QByteArray &requestType = packet.extractChannelRequestType(); + if (requestType == SshIncomingPacket::ExitStatusType) + handleExitStatus(packet.extractChannelExitStatus()); + else if (requestType == SshIncomingPacket::ExitSignalType) + handleExitSignal(packet.extractChannelExitSignal()); + else if (requestType != "eow@openssh.com") // Suppress warning for this one, as it's sent all the time. + qCWarning(sshLog, "Ignoring unknown request type '%s'", requestType.data()); +} + +int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data) +{ + checkChannelActive(); + + const int bytesToDeliver = qMin(data.size(), maxDataSize()); + if (bytesToDeliver != data.size()) + qCWarning(sshLog, "Misbehaving server does not respect local window, clipping."); + + m_localWindowSize -= bytesToDeliver; + if (m_localWindowSize < maxPacketSize()) { + m_localWindowSize += maxPacketSize(); + m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize()); + } + return bytesToDeliver; +} + +void AbstractSshChannel::closeChannel() +{ + if (m_state == CloseRequested) { + m_timeoutTimer.stop(); + } else if (m_state != Closed) { + if (m_state == Inactive) { + setChannelState(Closed); + } else { + const ChannelState oldState = m_state; + setChannelState(CloseRequested); + if (m_remoteChannel != NoChannel) { + m_sendFacility.sendChannelEofPacket(m_remoteChannel); + m_sendFacility.sendChannelClosePacket(m_remoteChannel); + } else { + QSSH_ASSERT(oldState == SessionRequested); + } + } + } +} + +void AbstractSshChannel::checkChannelActive() +{ + if (channelState() == Inactive || channelState() == Closed) + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Channel not open."); +} + +quint32 AbstractSshChannel::maxDataSize() const +{ + return qMin(m_localWindowSize, maxPacketSize()); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshchannel_p.h b/client/3rd/QtSsh/src/ssh/sshchannel_p.h new file mode 100644 index 00000000..a5556770 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshchannel_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +namespace QSsh { +namespace Internal { + +struct SshChannelExitSignal; +struct SshChannelExitStatus; +class SshIncomingPacket; +class SshSendFacility; + +class AbstractSshChannel : public QObject +{ + Q_OBJECT +public: + enum ChannelState { + Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed + }; + + quint32 localChannelId() const { return m_localChannel; } + quint32 remoteChannel() const { return m_remoteChannel; } + + virtual void handleChannelSuccess() = 0; + virtual void handleChannelFailure() = 0; + + void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize, + quint32 remoteMaxPacketSize); + void handleOpenFailure(const QString &reason); + void handleWindowAdjust(quint32 bytesToAdd); + void handleChannelEof(); + void handleChannelClose(); + void handleChannelData(const QByteArray &data); + void handleChannelExtendedData(quint32 type, const QByteArray &data); + void handleChannelRequest(const SshIncomingPacket &packet); + + void closeChannel(); + + virtual ~AbstractSshChannel(); + + static const int ReplyTimeout = 10000; // milli seconds + ChannelState channelState() const { return m_state; } + +signals: + void timeout(); + void eof(); + +protected: + AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility); + + void setChannelState(ChannelState state); + + void requestSessionStart(); + void sendData(const QByteArray &data); + + static quint32 initialWindowSize(); + static quint32 maxPacketSize(); + + quint32 maxDataSize() const; + void checkChannelActive(); + + SshSendFacility &m_sendFacility; + QTimer m_timeoutTimer; + +private: + virtual void handleOpenSuccessInternal() = 0; + virtual void handleOpenFailureInternal(const QString &reason) = 0; + virtual void handleChannelDataInternal(const QByteArray &data) = 0; + virtual void handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data) = 0; + virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0; + virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0; + + virtual void closeHook() = 0; + + void flushSendBuffer(); + int handleChannelOrExtendedChannelData(const QByteArray &data); + + const quint32 m_localChannel; + quint32 m_remoteChannel; + quint32 m_localWindowSize; + quint32 m_remoteWindowSize; + quint32 m_remoteMaxPacketSize; + ChannelState m_state; + QByteArray m_sendBuffer; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshchannelmanager.cpp b/client/3rd/QtSsh/src/ssh/sshchannelmanager.cpp new file mode 100644 index 00000000..364d1dcf --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshchannelmanager.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshchannelmanager_p.h" + +#include "sftpchannel.h" +#include "sftpchannel_p.h" +#include "sshdirecttcpiptunnel.h" +#include "sshdirecttcpiptunnel_p.h" +#include "sshforwardedtcpiptunnel.h" +#include "sshforwardedtcpiptunnel_p.h" +#include "sshincomingpacket_p.h" +#include "sshlogging_p.h" +#include "sshremoteprocess.h" +#include "sshremoteprocess_p.h" +#include "sshsendfacility_p.h" +#include "sshtcpipforwardserver.h" +#include "sshtcpipforwardserver_p.h" + +#include + +namespace QSsh { +namespace Internal { + +SshChannelManager::SshChannelManager(SshSendFacility &sendFacility, + QObject *parent) + : QObject(parent), m_sendFacility(sendFacility), m_nextLocalChannelId(0) +{ +} + +void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet) +{ + lookupChannel(packet.extractRecipientChannel()) + ->handleChannelRequest(packet); +} + +void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet) +{ + SshChannelOpen channelOpen = packet.extractChannelOpen(); + + SshTcpIpForwardServer::Ptr server; + + foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) { + if (candidate->port() == channelOpen.remotePort + && candidate->bindAddress().toUtf8() == channelOpen.remoteAddress) { + server = candidate; + break; + } + }; + + + if (server.isNull()) { + // Apparently the server knows a remoteAddress we are not aware of. There are plenty of ways + // to make that happen: /etc/hosts on the server, different writings for localhost, + // different DNS servers, ... + // Rather than trying to figure that out, we just use the first listening forwarder with the + // same port. + foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) { + if (candidate->port() == channelOpen.remotePort) { + server = candidate; + break; + } + }; + } + + if (server.isNull()) { + SshOpenFailureType reason = (channelOpen.remotePort == 0) ? + SSH_OPEN_UNKNOWN_CHANNEL_TYPE : SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; + try { + m_sendFacility.sendChannelOpenFailurePacket(channelOpen.remoteChannel, reason, + QByteArray()); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + } + return; + } + + SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++, + m_sendFacility)); + tunnel->d->handleOpenSuccess(channelOpen.remoteChannel, channelOpen.remoteWindowSize, + channelOpen.remoteMaxPacketSize); + tunnel->open(QIODevice::ReadWrite); + server->setNewConnection(tunnel); + insertChannel(tunnel->d, tunnel); +} + +void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet) +{ + const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure(); + ChannelIterator it = lookupChannelAsIterator(failure.localChannel); + try { + it.value()->handleOpenFailure(failure.reasonString); + } catch (const SshServerException &e) { + removeChannel(it); + throw e; + } + removeChannel(it); +} + +void SshChannelManager::handleChannelOpenConfirmation(const SshIncomingPacket &packet) +{ + const SshChannelOpenConfirmation &confirmation + = packet.extractChannelOpenConfirmation(); + lookupChannel(confirmation.localChannel)->handleOpenSuccess(confirmation.remoteChannel, + confirmation.remoteWindowSize, confirmation.remoteMaxPacketSize); +} + +void SshChannelManager::handleChannelSuccess(const SshIncomingPacket &packet) +{ + lookupChannel(packet.extractRecipientChannel())->handleChannelSuccess(); +} + +void SshChannelManager::handleChannelFailure(const SshIncomingPacket &packet) +{ + lookupChannel(packet.extractRecipientChannel())->handleChannelFailure(); +} + +void SshChannelManager::handleChannelWindowAdjust(const SshIncomingPacket &packet) +{ + const SshChannelWindowAdjust adjust = packet.extractWindowAdjust(); + lookupChannel(adjust.localChannel)->handleWindowAdjust(adjust.bytesToAdd); +} + +void SshChannelManager::handleChannelData(const SshIncomingPacket &packet) +{ + const SshChannelData &data = packet.extractChannelData(); + lookupChannel(data.localChannel)->handleChannelData(data.data); +} + +void SshChannelManager::handleChannelExtendedData(const SshIncomingPacket &packet) +{ + const SshChannelExtendedData &data = packet.extractChannelExtendedData(); + lookupChannel(data.localChannel)->handleChannelExtendedData(data.type, data.data); +} + +void SshChannelManager::handleChannelEof(const SshIncomingPacket &packet) +{ + AbstractSshChannel * const channel + = lookupChannel(packet.extractRecipientChannel(), true); + if (channel) + channel->handleChannelEof(); +} + +void SshChannelManager::handleChannelClose(const SshIncomingPacket &packet) +{ + const quint32 channelId = packet.extractRecipientChannel(); + + ChannelIterator it = lookupChannelAsIterator(channelId, true); + if (it != m_channels.end()) { + it.value()->handleChannelClose(); + removeChannel(it); + } +} + +void SshChannelManager::handleRequestSuccess(const SshIncomingPacket &packet) +{ + if (m_waitingForwardServers.isEmpty()) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected request success packet.", + tr("Unexpected request success packet.")); + } + SshTcpIpForwardServer::Ptr server = m_waitingForwardServers.takeFirst(); + if (server->state() == SshTcpIpForwardServer::Closing) { + server->setClosed(); + } else if (server->state() == SshTcpIpForwardServer::Initializing) { + quint16 port = server->port(); + if (port == 0) + port = packet.extractRequestSuccess().bindPort; + server->setListening(port); + m_listeningForwardServers.append(server); + } else { + QSSH_ASSERT(false); + } +} + +void SshChannelManager::handleRequestFailure(const SshIncomingPacket &packet) +{ + Q_UNUSED(packet); + if (m_waitingForwardServers.isEmpty()) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected request failure packet.", + tr("Unexpected request failure packet.")); + } + SshTcpIpForwardServer::Ptr tunnel = m_waitingForwardServers.takeFirst(); + tunnel->setClosed(); +} + +SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId, + bool allowNotFound) +{ + ChannelIterator it = m_channels.find(channelId); + if (it == m_channels.end() && !allowNotFound) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid channel id.", + tr("Invalid channel id %1").arg(channelId)); + } + return it; +} + +AbstractSshChannel *SshChannelManager::lookupChannel(quint32 channelId, + bool allowNotFound) +{ + ChannelIterator it = lookupChannelAsIterator(channelId, allowNotFound); + return it == m_channels.end() ? 0 : it.value(); +} + +QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command) +{ + SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility)); + insertChannel(proc->d, proc); + return proc; +} + +QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteShell() +{ + SshRemoteProcess::Ptr proc(new SshRemoteProcess(m_nextLocalChannelId++, m_sendFacility)); + insertChannel(proc->d, proc); + return proc; +} + +QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel() +{ + SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility)); + insertChannel(sftp->d, sftp); + return sftp; +} + +SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort) +{ + SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++, + originatingHost, originatingPort, remoteHost, remotePort, m_sendFacility)); + insertChannel(tunnel->d, tunnel); + return tunnel; +} + +SshTcpIpForwardServer::Ptr SshChannelManager::createForwardServer(const QString &remoteHost, + quint16 remotePort) +{ + SshTcpIpForwardServer::Ptr server(new SshTcpIpForwardServer(remoteHost, remotePort, + m_sendFacility)); + connect(server.data(), &SshTcpIpForwardServer::stateChanged, + this, [this, server](SshTcpIpForwardServer::State state) { + switch (state) { + case SshTcpIpForwardServer::Closing: + m_listeningForwardServers.removeOne(server); + // fall through + case SshTcpIpForwardServer::Initializing: + m_waitingForwardServers.append(server); + break; + case SshTcpIpForwardServer::Listening: + case SshTcpIpForwardServer::Inactive: + break; + } + }); + return server; +} + +void SshChannelManager::insertChannel(AbstractSshChannel *priv, + const QSharedPointer &pub) +{ + connect(priv, &AbstractSshChannel::timeout, this, &SshChannelManager::timeout); + m_channels.insert(priv->localChannelId(), priv); + m_sessions.insert(priv, pub); +} + +int SshChannelManager::closeAllChannels(CloseAllMode mode) +{ + int count = 0; + for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) { + AbstractSshChannel * const channel = it.value(); + QSSH_ASSERT(channel->channelState() != AbstractSshChannel::Closed); + if (channel->channelState() != AbstractSshChannel::CloseRequested) { + channel->closeChannel(); + ++count; + } + } + if (mode == CloseAllAndReset) { + m_channels.clear(); + m_sessions.clear(); + } + return count; +} + +int SshChannelManager::channelCount() const +{ + return m_channels.count(); +} + +void SshChannelManager::removeChannel(ChannelIterator it) +{ + if (it == m_channels.end()) { + throw SshClientException(SshInternalError, + QLatin1String("Internal error: Unexpected channel lookup failure")); + } + const int removeCount = m_sessions.remove(it.value()); + if (removeCount != 1) { + throw SshClientException(SshInternalError, + QString::fromLatin1("Internal error: Unexpected session count %1 for channel.") + .arg(removeCount)); + } + m_channels.erase(it); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshchannelmanager_p.h b/client/3rd/QtSsh/src/ssh/sshchannelmanager_p.h new file mode 100644 index 00000000..413ed12c --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshchannelmanager_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace QSsh { +class SftpChannel; +class SshDirectTcpIpTunnel; +class SshRemoteProcess; +class SshTcpIpForwardServer; + +namespace Internal { + +class AbstractSshChannel; +class SshIncomingPacket; +class SshSendFacility; + +class SshChannelManager : public QObject +{ + Q_OBJECT +public: + SshChannelManager(SshSendFacility &sendFacility, QObject *parent); + + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createRemoteShell(); + QSharedPointer createSftpChannel(); + QSharedPointer createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort); + QSharedPointer createForwardServer(const QString &remoteHost, + quint16 remotePort); + + int channelCount() const; + enum CloseAllMode { CloseAllRegular, CloseAllAndReset }; + int closeAllChannels(CloseAllMode mode); + + void handleChannelRequest(const SshIncomingPacket &packet); + void handleChannelOpen(const SshIncomingPacket &packet); + void handleChannelOpenFailure(const SshIncomingPacket &packet); + void handleChannelOpenConfirmation(const SshIncomingPacket &packet); + void handleChannelSuccess(const SshIncomingPacket &packet); + void handleChannelFailure(const SshIncomingPacket &packet); + void handleChannelWindowAdjust(const SshIncomingPacket &packet); + void handleChannelData(const SshIncomingPacket &packet); + void handleChannelExtendedData(const SshIncomingPacket &packet); + void handleChannelEof(const SshIncomingPacket &packet); + void handleChannelClose(const SshIncomingPacket &packet); + void handleRequestSuccess(const SshIncomingPacket &packet); + void handleRequestFailure(const SshIncomingPacket &packet); + +signals: + void timeout(); + +private: + typedef QHash::Iterator ChannelIterator; + + ChannelIterator lookupChannelAsIterator(quint32 channelId, + bool allowNotFound = false); + AbstractSshChannel *lookupChannel(quint32 channelId, + bool allowNotFound = false); + void removeChannel(ChannelIterator it); + void insertChannel(AbstractSshChannel *priv, + const QSharedPointer &pub); + + SshSendFacility &m_sendFacility; + QHash m_channels; + QHash > m_sessions; + quint32 m_nextLocalChannelId; + QList> m_waitingForwardServers; + QList> m_listeningForwardServers; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshconnection.cpp b/client/3rd/QtSsh/src/ssh/sshconnection.cpp new file mode 100644 index 00000000..5b5a20ca --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshconnection.cpp @@ -0,0 +1,864 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshconnection.h" +#include "sshconnection_p.h" + +#include "sftpchannel.h" +#include "sshcapabilities_p.h" +#include "sshchannelmanager_p.h" +#include "sshcryptofacility_p.h" +#include "sshdirecttcpiptunnel.h" +#include "sshtcpipforwardserver.h" +#include "sshexception_p.h" +#include "sshinit_p.h" +#include "sshkeyexchange_p.h" +#include "sshlogging_p.h" +#include "sshremoteprocess.h" + +#include + +#include +#include +#include +#include +#include +#include + +/*! + \class QSsh::SshConnection + + \brief The SshConnection class provides an SSH connection, implementing + protocol version 2.0. + + It can spawn channels for remote execution and SFTP operations (version 3). + It operates asynchronously (non-blocking) and is not thread-safe. +*/ + +namespace QSsh { + +const QByteArray ClientId("SSH-2.0-QtCreator\r\n"); + +SshConnectionParameters::SshConnectionParameters() : + timeout(0), authenticationType(AuthenticationTypePublicKey), port(0), + hostKeyCheckingMode(SshHostKeyCheckingNone) +{ + options |= SshIgnoreDefaultProxy; + options |= SshEnableStrictConformanceChecks; +} + +static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return p1.host == p2.host && p1.userName == p2.userName + && p1.authenticationType == p2.authenticationType + && (p1.authenticationType == SshConnectionParameters::AuthenticationTypePassword ? + p1.password == p2.password : p1.privateKeyFile == p2.privateKeyFile) + && p1.hostKeyCheckingMode == p2.hostKeyCheckingMode + && p1.timeout == p2.timeout && p1.port == p2.port; +} + +bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return equals(p1, p2); +} + +bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return !equals(p1, p2); +} + + +SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent) + : QObject(parent) +{ + Internal::initSsh(); + qRegisterMetaType("QSsh::SshError"); + qRegisterMetaType("QSsh::SftpJobId"); + qRegisterMetaType("QSsh::SftpFileInfo"); + qRegisterMetaType >("QList"); + + d = new Internal::SshConnectionPrivate(this, serverInfo); + connect(d, &Internal::SshConnectionPrivate::connected, this, &SshConnection::connected, + Qt::QueuedConnection); + connect(d, &Internal::SshConnectionPrivate::dataAvailable, this, + &SshConnection::dataAvailable, Qt::QueuedConnection); + connect(d, &Internal::SshConnectionPrivate::disconnected, this, &SshConnection::disconnected, + Qt::QueuedConnection); + connect(d, &Internal::SshConnectionPrivate::error, this, + &SshConnection::error, Qt::QueuedConnection); +} + +void SshConnection::connectToHost() +{ + d->connectToHost(); +} + +void SshConnection::disconnectFromHost() +{ + d->closeConnection(Internal::SSH_DISCONNECT_BY_APPLICATION, SshNoError, "", + QString()); +} + +SshConnection::State SshConnection::state() const +{ + switch (d->state()) { + case Internal::SocketUnconnected: + return Unconnected; + case Internal::ConnectionEstablished: + return Connected; + default: + return Connecting; + } +} + +SshError SshConnection::errorState() const +{ + return d->errorState(); +} + +QString SshConnection::errorString() const +{ + return d->errorString(); +} + +SshConnectionParameters SshConnection::connectionParameters() const +{ + return d->m_connParams; +} + +SshConnectionInfo SshConnection::connectionInfo() const +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshConnectionInfo()); + + return SshConnectionInfo(d->m_socket->localAddress(), d->m_socket->localPort(), + d->m_socket->peerAddress(), d->m_socket->peerPort()); +} + +SshConnection::~SshConnection() +{ + disconnect(); + disconnectFromHost(); + delete d; +} + +QSharedPointer SshConnection::createRemoteProcess(const QByteArray &command) +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer()); + return d->createRemoteProcess(command); +} + +QSharedPointer SshConnection::createRemoteShell() +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer()); + return d->createRemoteShell(); +} + +QSharedPointer SshConnection::createSftpChannel() +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer()); + return d->createSftpChannel(); +} + +SshDirectTcpIpTunnel::Ptr SshConnection::createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort) +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr()); + return d->createDirectTunnel(originatingHost, originatingPort, remoteHost, remotePort); +} + +QSharedPointer SshConnection::createForwardServer(const QString &remoteHost, + quint16 remotePort) +{ + QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshTcpIpForwardServer::Ptr()); + return d->createForwardServer(remoteHost, remotePort); +} + +int SshConnection::closeAllChannels() +{ + try { + return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular); + } catch (const std::exception &e) { + qCWarning(Internal::sshLog, "%s: %s", Q_FUNC_INFO, e.what()); + return -1; + } +} + +int SshConnection::channelCount() const +{ + return d->m_channelManager->channelCount(); +} + +namespace Internal { + +SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn, + const SshConnectionParameters &serverInfo) + : m_socket(new QTcpSocket(this)), m_state(SocketUnconnected), + m_sendFacility(m_socket), + m_channelManager(new SshChannelManager(m_sendFacility, this)), + m_connParams(serverInfo), m_error(SshNoError), m_ignoreNextPacket(false), + m_conn(conn) +{ + setupPacketHandlers(); + m_socket->setProxy((m_connParams.options & SshIgnoreDefaultProxy) + ? QNetworkProxy::NoProxy : QNetworkProxy::DefaultProxy); + m_timeoutTimer.setSingleShot(true); + m_timeoutTimer.setInterval(m_connParams.timeout * 1000); + m_keepAliveTimer.setSingleShot(true); + m_keepAliveTimer.setInterval(10000); + connect(m_channelManager, &SshChannelManager::timeout, + this, &SshConnectionPrivate::handleTimeout); +} + +SshConnectionPrivate::~SshConnectionPrivate() +{ + disconnect(); +} + +void SshConnectionPrivate::setupPacketHandlers() +{ + typedef SshConnectionPrivate This; + + setupPacketHandler(SSH_MSG_KEXINIT, StateList() << SocketConnected + << ConnectionEstablished, &This::handleKeyExchangeInitPacket); + setupPacketHandler(SSH_MSG_KEXDH_REPLY, StateList() << SocketConnected + << ConnectionEstablished, &This::handleKeyExchangeReplyPacket); + + setupPacketHandler(SSH_MSG_NEWKEYS, StateList() << SocketConnected + << ConnectionEstablished, &This::handleNewKeysPacket); + setupPacketHandler(SSH_MSG_SERVICE_ACCEPT, + StateList() << UserAuthServiceRequested, + &This::handleServiceAcceptPacket); + if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypePassword + || m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) { + setupPacketHandler(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, + StateList() << UserAuthRequested, &This::handlePasswordExpiredPacket); + } + setupPacketHandler(SSH_MSG_GLOBAL_REQUEST, + StateList() << ConnectionEstablished, &This::handleGlobalRequest); + + const StateList authReqList = StateList() << UserAuthRequested; + setupPacketHandler(SSH_MSG_USERAUTH_BANNER, authReqList, + &This::handleUserAuthBannerPacket); + setupPacketHandler(SSH_MSG_USERAUTH_SUCCESS, authReqList, + &This::handleUserAuthSuccessPacket); + setupPacketHandler(SSH_MSG_USERAUTH_FAILURE, authReqList, + &This::handleUserAuthFailurePacket); + if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeKeyboardInteractive + || m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) { + setupPacketHandler(SSH_MSG_USERAUTH_INFO_REQUEST, authReqList, + &This::handleUserAuthInfoRequestPacket); + } + + const StateList connectedList + = StateList() << ConnectionEstablished; + setupPacketHandler(SSH_MSG_CHANNEL_REQUEST, connectedList, + &This::handleChannelRequest); + setupPacketHandler(SSH_MSG_CHANNEL_OPEN, connectedList, + &This::handleChannelOpen); + setupPacketHandler(SSH_MSG_CHANNEL_OPEN_FAILURE, connectedList, + &This::handleChannelOpenFailure); + setupPacketHandler(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, connectedList, + &This::handleChannelOpenConfirmation); + setupPacketHandler(SSH_MSG_CHANNEL_SUCCESS, connectedList, + &This::handleChannelSuccess); + setupPacketHandler(SSH_MSG_CHANNEL_FAILURE, connectedList, + &This::handleChannelFailure); + setupPacketHandler(SSH_MSG_CHANNEL_WINDOW_ADJUST, connectedList, + &This::handleChannelWindowAdjust); + setupPacketHandler(SSH_MSG_CHANNEL_DATA, connectedList, + &This::handleChannelData); + setupPacketHandler(SSH_MSG_CHANNEL_EXTENDED_DATA, connectedList, + &This::handleChannelExtendedData); + + const StateList connectedOrClosedList + = StateList() << SocketUnconnected << ConnectionEstablished; + setupPacketHandler(SSH_MSG_CHANNEL_EOF, connectedOrClosedList, + &This::handleChannelEof); + setupPacketHandler(SSH_MSG_CHANNEL_CLOSE, connectedOrClosedList, + &This::handleChannelClose); + + setupPacketHandler(SSH_MSG_DISCONNECT, StateList() << SocketConnected + << UserAuthServiceRequested << UserAuthRequested + << ConnectionEstablished, &This::handleDisconnect); + + setupPacketHandler(SSH_MSG_UNIMPLEMENTED, + StateList() << ConnectionEstablished, &This::handleUnimplementedPacket); + + setupPacketHandler(SSH_MSG_REQUEST_SUCCESS, connectedList, + &This::handleRequestSuccess); + setupPacketHandler(SSH_MSG_REQUEST_FAILURE, connectedList, + &This::handleRequestFailure); +} + +void SshConnectionPrivate::setupPacketHandler(SshPacketType type, + const SshConnectionPrivate::StateList &states, + SshConnectionPrivate::PacketHandler handler) +{ + m_packetHandlers.insert(type, HandlerInStates(states, handler)); +} + +void SshConnectionPrivate::handleSocketConnected() +{ + m_state = SocketConnected; + sendData(ClientId); +} + +void SshConnectionPrivate::handleIncomingData() +{ + if (m_state == SocketUnconnected) + return; // For stuff queued in the event loop after we've called closeConnection(); + + try { + if (!canUseSocket()) + return; + m_incomingData += m_socket->readAll(); + qCDebug(sshLog, "state = %d, remote data size = %d", m_state, m_incomingData.count()); + if (m_serverId.isEmpty()) + handleServerId(); + handlePackets(); + } catch (const SshServerException &e) { + closeConnection(e.error, SshProtocolError, e.errorStringServer, + tr("SSH Protocol error: %1").arg(e.errorStringUser)); + } catch (const SshClientException &e) { + closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "", + e.errorString); + } catch (const std::exception &e) { + closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "", + tr("Botan library exception: %1").arg(QString::fromLatin1(e.what()))); + } +} + +// RFC 4253, 4.2. +void SshConnectionPrivate::handleServerId() +{ + qCDebug(sshLog, "%s: incoming data size = %d, incoming data = '%s'", + Q_FUNC_INFO, m_incomingData.count(), m_incomingData.data()); + const int newLinePos = m_incomingData.indexOf('\n'); + if (newLinePos == -1) + return; // Not enough data yet. + + // Lines not starting with "SSH-" are ignored. + if (!m_incomingData.startsWith("SSH-")) { + m_incomingData.remove(0, newLinePos + 1); + m_serverHasSentDataBeforeId = true; + return; + } + + if (newLinePos > 255 - 1) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Identification string too long.", + tr("Server identification string is %n characters long, but the maximum " + "allowed length is 255.", 0, newLinePos + 1)); + } + + const bool hasCarriageReturn = m_incomingData.at(newLinePos - 1) == '\r'; + m_serverId = m_incomingData.left(newLinePos); + if (hasCarriageReturn) + m_serverId.chop(1); + m_incomingData.remove(0, newLinePos + 1); + + if (m_serverId.contains('\0')) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Identification string contains illegal NUL character.", + tr("Server identification string contains illegal NUL character.")); + } + + // "printable US-ASCII characters, with the exception of whitespace characters + // and the minus sign" + QString legalString = QLatin1String("[]!\"#$!&'()*+,./0-9:;<=>?@A-Z[\\\\^_`a-z{|}~]+"); + const QRegExp versionIdpattern(QString::fromLatin1("SSH-(%1)-%1(?: .+)?").arg(legalString)); + if (!versionIdpattern.exactMatch(QString::fromLatin1(m_serverId))) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Identification string is invalid.", + tr("Server Identification string \"%1\" is invalid.") + .arg(QString::fromLatin1(m_serverId))); + } + const QString serverProtoVersion = versionIdpattern.cap(1); + if (serverProtoVersion != QLatin1String("2.0") && serverProtoVersion != QLatin1String("1.99")) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, + "Invalid protocol version.", + tr("Server protocol version is \"%1\", but needs to be 2.0 or 1.99.") + .arg(serverProtoVersion)); + } + + if (m_connParams.options & SshEnableStrictConformanceChecks) { + if (serverProtoVersion == QLatin1String("2.0") && !hasCarriageReturn) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Identification string is invalid.", + tr("Server identification string is invalid (missing carriage return).")); + } + + if (serverProtoVersion == QLatin1String("1.99") && m_serverHasSentDataBeforeId) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "No extra data preceding identification string allowed for 1.99.", + tr("Server reports protocol version 1.99, but sends data " + "before the identification string, which is not allowed.")); + } + } + + m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility)); + m_keyExchange->sendKexInitPacket(m_serverId); + m_keyExchangeState = KexInitSent; +} + +void SshConnectionPrivate::handlePackets() +{ + m_incomingPacket.consumeData(m_incomingData); + while (m_incomingPacket.isComplete()) { + handleCurrentPacket(); + m_incomingPacket.clear(); + m_incomingPacket.consumeData(m_incomingData); + } +} + +void SshConnectionPrivate::handleCurrentPacket() +{ + Q_ASSERT(m_incomingPacket.isComplete()); + Q_ASSERT(m_keyExchangeState == DhInitSent || !m_ignoreNextPacket); + + if (m_ignoreNextPacket) { + m_ignoreNextPacket = false; + return; + } + + QHash::ConstIterator it + = m_packetHandlers.constFind(m_incomingPacket.type()); + if (it == m_packetHandlers.constEnd()) { + m_sendFacility.sendMsgUnimplementedPacket(m_incomingPacket.serverSeqNr()); + return; + } + if (!it.value().first.contains(m_state)) { + handleUnexpectedPacket(); + return; + } + (this->*it.value().second)(); +} + +void SshConnectionPrivate::handleKeyExchangeInitPacket() +{ + if (m_keyExchangeState != NoKeyExchange + && m_keyExchangeState != KexInitSent) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", tr("Unexpected packet of type %1.") + .arg(m_incomingPacket.type())); + } + + // Server-initiated re-exchange. + if (m_keyExchangeState == NoKeyExchange) { + m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility)); + m_keyExchange->sendKexInitPacket(m_serverId); + } + + // If the server sends a guessed packet, the guess must be wrong, + // because the algorithms we support require us to initiate the + // key exchange. + if (m_keyExchange->sendDhInitPacket(m_incomingPacket)) + m_ignoreNextPacket = true; + + m_keyExchangeState = DhInitSent; +} + +void SshConnectionPrivate::handleKeyExchangeReplyPacket() +{ + if (m_keyExchangeState != DhInitSent) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", tr("Unexpected packet of type %1.") + .arg(m_incomingPacket.type())); + } + + m_keyExchange->sendNewKeysPacket(m_incomingPacket, + ClientId.left(ClientId.size() - 2)); + m_sendFacility.recreateKeys(*m_keyExchange); + m_keyExchangeState = NewKeysSent; +} + +void SshConnectionPrivate::handleNewKeysPacket() +{ + if (m_keyExchangeState != NewKeysSent) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", tr("Unexpected packet of type %1.") + .arg(m_incomingPacket.type())); + } + + m_incomingPacket.recreateKeys(*m_keyExchange); + m_keyExchange.reset(); + m_keyExchangeState = NoKeyExchange; + + if (m_state == SocketConnected) { + m_sendFacility.sendUserAuthServiceRequestPacket(); + m_state = UserAuthServiceRequested; + } +} + +void SshConnectionPrivate::handleServiceAcceptPacket() +{ + switch (m_connParams.authenticationType) { + case SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods: + m_triedAllPasswordBasedMethods = false; + // Fall-through. + case SshConnectionParameters::AuthenticationTypePassword: + m_sendFacility.sendUserAuthByPasswordRequestPacket(m_connParams.userName.toUtf8(), + SshCapabilities::SshConnectionService, m_connParams.password.toUtf8()); + break; + case SshConnectionParameters::AuthenticationTypeKeyboardInteractive: + m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket(m_connParams.userName.toUtf8(), + SshCapabilities::SshConnectionService); + break; + case SshConnectionParameters::AuthenticationTypePublicKey: + m_sendFacility.sendUserAuthByPublicKeyRequestPacket(m_connParams.userName.toUtf8(), + SshCapabilities::SshConnectionService); + break; + } + m_state = UserAuthRequested; +} + +void SshConnectionPrivate::handlePasswordExpiredPacket() +{ + if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + && m_triedAllPasswordBasedMethods) { + // This means we just tried to authorize via "keyboard-interactive", in which case + // this type of packet is not allowed. + handleUnexpectedPacket(); + return; + } + throw SshClientException(SshAuthenticationError, tr("Password expired.")); +} + +void SshConnectionPrivate::handleUserAuthInfoRequestPacket() +{ + if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + && !m_triedAllPasswordBasedMethods) { + // This means we just tried to authorize via "password", in which case + // this type of packet is not allowed. + handleUnexpectedPacket(); + return; + } + + const SshUserAuthInfoRequestPacket requestPacket + = m_incomingPacket.extractUserAuthInfoRequest(); + QStringList responses; + responses.reserve(requestPacket.prompts.count()); + + // Not very interactive, admittedly, but we don't want to be for now. + for (int i = 0; i < requestPacket.prompts.count(); ++i) + responses << m_connParams.password; + m_sendFacility.sendUserAuthInfoResponsePacket(responses); +} + +void SshConnectionPrivate::handleUserAuthBannerPacket() +{ + emit dataAvailable(m_incomingPacket.extractUserAuthBanner().message); +} + +void SshConnectionPrivate::handleUnexpectedPacket() +{ + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", tr("Unexpected packet of type %1.") + .arg(m_incomingPacket.type())); +} + +void SshConnectionPrivate::handleGlobalRequest() +{ + m_sendFacility.sendRequestFailurePacket(); +} + +void SshConnectionPrivate::handleUserAuthSuccessPacket() +{ + m_state = ConnectionEstablished; + m_timeoutTimer.stop(); + emit connected(); + m_lastInvalidMsgSeqNr = InvalidSeqNr; + connect(&m_keepAliveTimer, &QTimer::timeout, this, &SshConnectionPrivate::sendKeepAlivePacket); + m_keepAliveTimer.start(); +} + +void SshConnectionPrivate::handleUserAuthFailurePacket() +{ + // TODO: Evaluate "authentications that can continue" field and act on it. + if (m_connParams.authenticationType + == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + && !m_triedAllPasswordBasedMethods) { + m_triedAllPasswordBasedMethods = true; + m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket( + m_connParams.userName.toUtf8(), + SshCapabilities::SshConnectionService); + return; + } + + m_timeoutTimer.stop(); + const QString errorMsg = m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypePublicKey + ? tr("Server rejected key.") : tr("Server rejected password."); + throw SshClientException(SshAuthenticationError, errorMsg); +} +void SshConnectionPrivate::handleDebugPacket() +{ + const SshDebug &msg = m_incomingPacket.extractDebug(); + if (msg.display) + emit dataAvailable(msg.message); +} + +void SshConnectionPrivate::handleUnimplementedPacket() +{ + const SshUnimplemented &msg = m_incomingPacket.extractUnimplemented(); + if (msg.invalidMsgSeqNr != m_lastInvalidMsgSeqNr) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet", tr("The server sent an unexpected SSH packet " + "of type SSH_MSG_UNIMPLEMENTED.")); + } + m_lastInvalidMsgSeqNr = InvalidSeqNr; + m_timeoutTimer.stop(); + m_keepAliveTimer.start(); +} + +void SshConnectionPrivate::handleChannelRequest() +{ + m_channelManager->handleChannelRequest(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelOpen() +{ + m_channelManager->handleChannelOpen(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelOpenFailure() +{ + m_channelManager->handleChannelOpenFailure(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelOpenConfirmation() +{ + m_channelManager->handleChannelOpenConfirmation(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelSuccess() +{ + m_channelManager->handleChannelSuccess(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelFailure() +{ + m_channelManager->handleChannelFailure(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelWindowAdjust() +{ + m_channelManager->handleChannelWindowAdjust(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelData() +{ + m_channelManager->handleChannelData(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelExtendedData() +{ + m_channelManager->handleChannelExtendedData(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelEof() +{ + m_channelManager->handleChannelEof(m_incomingPacket); +} + +void SshConnectionPrivate::handleChannelClose() +{ + m_channelManager->handleChannelClose(m_incomingPacket); +} + +void SshConnectionPrivate::handleDisconnect() +{ + const SshDisconnect msg = m_incomingPacket.extractDisconnect(); + throw SshServerException(SSH_DISCONNECT_CONNECTION_LOST, + "", tr("Server closed connection: %1").arg(msg.description)); +} + +void SshConnectionPrivate::handleRequestSuccess() +{ + m_channelManager->handleRequestSuccess(m_incomingPacket); +} + +void SshConnectionPrivate::handleRequestFailure() +{ + m_channelManager->handleRequestFailure(m_incomingPacket); +} + +void SshConnectionPrivate::sendData(const QByteArray &data) +{ + if (canUseSocket()) + m_socket->write(data); +} + +void SshConnectionPrivate::handleSocketDisconnected() +{ + closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshClosedByServerError, + "Connection closed unexpectedly.", + tr("Connection closed unexpectedly.")); +} + +void SshConnectionPrivate::handleSocketError() +{ + if (m_error == SshNoError) { + closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshSocketError, + "Network error", m_socket->errorString()); + } +} + +void SshConnectionPrivate::handleTimeout() +{ + closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshTimeoutError, "", + tr("Timeout waiting for reply from server.")); +} + +void SshConnectionPrivate::sendKeepAlivePacket() +{ + // This type of message is not allowed during key exchange. + if (m_keyExchangeState != NoKeyExchange) { + m_keepAliveTimer.start(); + return; + } + + Q_ASSERT(m_lastInvalidMsgSeqNr == InvalidSeqNr); + m_lastInvalidMsgSeqNr = m_sendFacility.nextClientSeqNr(); + m_sendFacility.sendInvalidPacket(); + m_timeoutTimer.start(); +} + +void SshConnectionPrivate::connectToHost() +{ + QSSH_ASSERT_AND_RETURN(m_state == SocketUnconnected); + + m_incomingData.clear(); + m_incomingPacket.reset(); + m_sendFacility.reset(); + m_error = SshNoError; + m_ignoreNextPacket = false; + m_errorString.clear(); + m_serverId.clear(); + m_serverHasSentDataBeforeId = false; + + try { + if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypePublicKey) + createPrivateKey(); + } catch (const SshClientException &ex) { + m_error = ex.error; + m_errorString = ex.errorString; + emit error(m_error); + return; + } + + connect(m_socket, &QAbstractSocket::connected, + this, &SshConnectionPrivate::handleSocketConnected); + connect(m_socket, &QIODevice::readyRead, + this, &SshConnectionPrivate::handleIncomingData); + connect(m_socket, + static_cast(&QAbstractSocket::error), + this, &SshConnectionPrivate::handleSocketError); + connect(m_socket, &QAbstractSocket::disconnected, + this, &SshConnectionPrivate::handleSocketDisconnected); + connect(&m_timeoutTimer, &QTimer::timeout, this, &SshConnectionPrivate::handleTimeout); + m_state = SocketConnecting; + m_keyExchangeState = NoKeyExchange; + m_timeoutTimer.start(); + m_socket->connectToHost(m_connParams.host, m_connParams.port); +} + +void SshConnectionPrivate::closeConnection(SshErrorCode sshError, + SshError userError, const QByteArray &serverErrorString, + const QString &userErrorString) +{ + // Prevent endless loops by recursive exceptions. + if (m_state == SocketUnconnected || m_error != SshNoError) + return; + + m_error = userError; + m_errorString = userErrorString; + m_timeoutTimer.stop(); + disconnect(m_socket, 0, this, 0); + disconnect(&m_timeoutTimer, 0, this, 0); + m_keepAliveTimer.stop(); + disconnect(&m_keepAliveTimer, 0, this, 0); + try { + m_channelManager->closeAllChannels(SshChannelManager::CloseAllAndReset); + m_sendFacility.sendDisconnectPacket(sshError, serverErrorString); + } catch (...) {} // Nothing sensible to be done here. + if (m_error != SshNoError) + emit error(userError); + if (m_state == ConnectionEstablished) + emit disconnected(); + if (canUseSocket()) + m_socket->disconnectFromHost(); + m_state = SocketUnconnected; +} + +bool SshConnectionPrivate::canUseSocket() const +{ + return m_socket->isValid() + && m_socket->state() == QAbstractSocket::ConnectedState; +} + +void SshConnectionPrivate::createPrivateKey() +{ + if (m_connParams.privateKeyFile.isEmpty()) + throw SshClientException(SshKeyFileError, tr("No private key file given.")); + QFile keyFile(m_connParams.privateKeyFile); + if (!keyFile.open(QIODevice::ReadOnly)) { + throw SshClientException(SshKeyFileError, + tr("Private key file error: %1").arg(keyFile.errorString())); + } + m_sendFacility.createAuthenticationKey(keyFile.readAll()); +} + +QSharedPointer SshConnectionPrivate::createRemoteProcess(const QByteArray &command) +{ + return m_channelManager->createRemoteProcess(command); +} + +QSharedPointer SshConnectionPrivate::createRemoteShell() +{ + return m_channelManager->createRemoteShell(); +} + +QSharedPointer SshConnectionPrivate::createSftpChannel() +{ + return m_channelManager->createSftpChannel(); +} + +SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort) +{ + return m_channelManager->createDirectTunnel(originatingHost, originatingPort, remoteHost, + remotePort); +} + +SshTcpIpForwardServer::Ptr SshConnectionPrivate::createForwardServer(const QString &bindAddress, + quint16 bindPort) +{ + return m_channelManager->createForwardServer(bindAddress, bindPort); +} + +const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast(-1); + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshconnection.h b/client/3rd/QtSsh/src/ssh/sshconnection.h new file mode 100644 index 00000000..071c97c0 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshconnection.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssherrors.h" +#include "sshhostkeydatabase.h" + +#include "ssh_global.h" + +#include +#include +#include +#include +#include +#include + +namespace QSsh { +class SftpChannel; +class SshDirectTcpIpTunnel; +class SshRemoteProcess; +class SshTcpIpForwardServer; + +namespace Internal { class SshConnectionPrivate; } + +enum SshConnectionOption { + SshIgnoreDefaultProxy = 0x1, + SshEnableStrictConformanceChecks = 0x2 +}; + +Q_DECLARE_FLAGS(SshConnectionOptions, SshConnectionOption) + +enum SshHostKeyCheckingMode { + SshHostKeyCheckingNone, + SshHostKeyCheckingStrict, + SshHostKeyCheckingAllowNoMatch, + SshHostKeyCheckingAllowMismatch +}; + +class QSSH_EXPORT SshConnectionParameters +{ +public: + enum AuthenticationType { + AuthenticationTypePassword, + AuthenticationTypePublicKey, + AuthenticationTypeKeyboardInteractive, + + // Some servers disable "password", others disable "keyboard-interactive". + AuthenticationTypeTryAllPasswordBasedMethods + }; + + SshConnectionParameters(); + + QString host; + QString userName; + QString password; + QString privateKeyFile; + int timeout; // In seconds. + AuthenticationType authenticationType; + quint16 port; + SshConnectionOptions options; + SshHostKeyCheckingMode hostKeyCheckingMode; + SshHostKeyDatabasePtr hostKeyDatabase; +}; + +QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2); +QSSH_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2); + +class QSSH_EXPORT SshConnectionInfo +{ +public: + SshConnectionInfo() : localPort(0), peerPort(0) {} + SshConnectionInfo(const QHostAddress &la, quint16 lp, const QHostAddress &pa, quint16 pp) + : localAddress(la), localPort(lp), peerAddress(pa), peerPort(pp) {} + + QHostAddress localAddress; + quint16 localPort; + QHostAddress peerAddress; + quint16 peerPort; +}; + +class QSSH_EXPORT SshConnection : public QObject +{ + Q_OBJECT + +public: + enum State { Unconnected, Connecting, Connected }; + + explicit SshConnection(const SshConnectionParameters &serverInfo, QObject *parent = 0); + + void connectToHost(); + void disconnectFromHost(); + State state() const; + SshError errorState() const; + QString errorString() const; + SshConnectionParameters connectionParameters() const; + SshConnectionInfo connectionInfo() const; + ~SshConnection(); + + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createRemoteShell(); + QSharedPointer createSftpChannel(); + QSharedPointer createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort); + QSharedPointer createForwardServer(const QString &remoteHost, + quint16 remotePort); + + // -1 if an error occurred, number of channels closed otherwise. + int closeAllChannels(); + + int channelCount() const; + +signals: + void connected(); + void disconnected(); + void dataAvailable(const QString &message); + void error(QSsh::SshError); + +private: + Internal::SshConnectionPrivate *d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshconnection_p.h b/client/3rd/QtSsh/src/ssh/sshconnection_p.h new file mode 100644 index 00000000..7c8198bf --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshconnection_p.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshconnection.h" +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" +#include "sshsendfacility_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QTcpSocket; +QT_END_NAMESPACE + +namespace QSsh { +class SftpChannel; +class SshRemoteProcess; +class SshDirectTcpIpTunnel; +class SshTcpIpForwardServer; + +namespace Internal { +class SshChannelManager; + +// NOTE: When you add stuff here, don't forget to update m_packetHandlers. +enum SshStateInternal { + SocketUnconnected, // initial and after disconnect + SocketConnecting, // After connectToHost() + SocketConnected, // After socket's connected() signal + UserAuthServiceRequested, + UserAuthRequested, + ConnectionEstablished // After service has been started + // ... +}; + +enum SshKeyExchangeState { + NoKeyExchange, + KexInitSent, + DhInitSent, + NewKeysSent, + KeyExchangeSuccess // After server's DH_REPLY message +}; + +class SshConnectionPrivate : public QObject +{ + Q_OBJECT + friend class QSsh::SshConnection; +public: + SshConnectionPrivate(SshConnection *conn, + const SshConnectionParameters &serverInfo); + ~SshConnectionPrivate(); + + void connectToHost(); + void closeConnection(SshErrorCode sshError, SshError userError, + const QByteArray &serverErrorString, const QString &userErrorString); + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createRemoteShell(); + QSharedPointer createSftpChannel(); + QSharedPointer createDirectTunnel(const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort); + QSharedPointer createForwardServer(const QString &remoteHost, + quint16 remotePort); + + SshStateInternal state() const { return m_state; } + SshError errorState() const { return m_error; } + QString errorString() const { return m_errorString; } + +signals: + void connected(); + void disconnected(); + void dataAvailable(const QString &message); + void error(QSsh::SshError); + +private: + void handleSocketConnected(); + void handleIncomingData(); + void handleSocketError(); + void handleSocketDisconnected(); + void handleTimeout(); + void sendKeepAlivePacket(); + + void handleServerId(); + void handlePackets(); + void handleCurrentPacket(); + void handleKeyExchangeInitPacket(); + void handleKeyExchangeReplyPacket(); + void handleNewKeysPacket(); + void handleServiceAcceptPacket(); + void handlePasswordExpiredPacket(); + void handleUserAuthInfoRequestPacket(); + void handleUserAuthSuccessPacket(); + void handleUserAuthFailurePacket(); + void handleUserAuthBannerPacket(); + void handleUnexpectedPacket(); + void handleGlobalRequest(); + void handleDebugPacket(); + void handleUnimplementedPacket(); + void handleChannelRequest(); + void handleChannelOpen(); + void handleChannelOpenFailure(); + void handleChannelOpenConfirmation(); + void handleChannelSuccess(); + void handleChannelFailure(); + void handleChannelWindowAdjust(); + void handleChannelData(); + void handleChannelExtendedData(); + void handleChannelEof(); + void handleChannelClose(); + void handleDisconnect(); + void handleRequestSuccess(); + void handleRequestFailure(); + + bool canUseSocket() const; + void createPrivateKey(); + + void sendData(const QByteArray &data); + + typedef void (SshConnectionPrivate::*PacketHandler)(); + typedef QList StateList; + void setupPacketHandlers(); + void setupPacketHandler(SshPacketType type, const StateList &states, + PacketHandler handler); + + typedef QPair HandlerInStates; + QHash m_packetHandlers; + + static const quint64 InvalidSeqNr; + + QTcpSocket *m_socket; + SshStateInternal m_state; + SshKeyExchangeState m_keyExchangeState; + SshIncomingPacket m_incomingPacket; + SshSendFacility m_sendFacility; + SshChannelManager * const m_channelManager; + const SshConnectionParameters m_connParams; + QByteArray m_incomingData; + SshError m_error; + QString m_errorString; + QScopedPointer m_keyExchange; + QTimer m_timeoutTimer; + QTimer m_keepAliveTimer; + bool m_ignoreNextPacket; + SshConnection *m_conn; + quint64 m_lastInvalidMsgSeqNr; + QByteArray m_serverId; + bool m_serverHasSentDataBeforeId; + bool m_triedAllPasswordBasedMethods; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshconnectionmanager.cpp b/client/3rd/QtSsh/src/ssh/sshconnectionmanager.cpp new file mode 100644 index 00000000..c6a35bd4 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshconnectionmanager.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshconnectionmanager.h" + +#include "sshconnection.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace QSsh { +namespace Internal { +class UnaquiredConnection { +public: + UnaquiredConnection(SshConnection *conn) : connection(conn), scheduledForRemoval(false) {} + + SshConnection *connection; + bool scheduledForRemoval; +}; +bool operator==(const UnaquiredConnection &c1, const UnaquiredConnection &c2) { + return c1.connection == c2.connection; +} +bool operator!=(const UnaquiredConnection &c1, const UnaquiredConnection &c2) { + return !(c1 == c2); +} + +class SshConnectionManager : public QObject +{ + Q_OBJECT + +public: + SshConnectionManager() + { + moveToThread(QCoreApplication::instance()->thread()); + connect(&m_removalTimer, &QTimer::timeout, + this, &SshConnectionManager::removeInactiveConnections); + m_removalTimer.start(150000); // For a total timeout of five minutes. + } + + ~SshConnectionManager() + { + foreach (const UnaquiredConnection &connection, m_unacquiredConnections) { + disconnect(connection.connection, 0, this, 0); + delete connection.connection; + } + + QSSH_ASSERT(m_acquiredConnections.isEmpty()); + QSSH_ASSERT(m_deprecatedConnections.isEmpty()); + } + + SshConnection *acquireConnection(const SshConnectionParameters &sshParams) + { + QMutexLocker locker(&m_listMutex); + + // Check in-use connections: + foreach (SshConnection * const connection, m_acquiredConnections) { + if (connection->connectionParameters() != sshParams) + continue; + + if (connection->thread() != QThread::currentThread()) + continue; + + if (m_deprecatedConnections.contains(connection)) // we were asked to no longer use this one... + continue; + + m_acquiredConnections.append(connection); + return connection; + } + + // Check cached open connections: + foreach (const UnaquiredConnection &c, m_unacquiredConnections) { + SshConnection * const connection = c.connection; + if (connection->state() != SshConnection::Connected + || connection->connectionParameters() != sshParams) + continue; + + if (connection->thread() != QThread::currentThread()) { + if (connection->channelCount() != 0) + continue; + QMetaObject::invokeMethod(this, "switchToCallerThread", + Qt::BlockingQueuedConnection, + Q_ARG(SshConnection *, connection), + Q_ARG(QObject *, QThread::currentThread())); + } + + m_unacquiredConnections.removeOne(c); + m_acquiredConnections.append(connection); + return connection; + } + + // create a new connection: + SshConnection * const connection = new SshConnection(sshParams); + connect(connection, &SshConnection::disconnected, + this, &SshConnectionManager::cleanup); + m_acquiredConnections.append(connection); + + return connection; + } + + void releaseConnection(SshConnection *connection) + { + QMutexLocker locker(&m_listMutex); + + const bool wasAquired = m_acquiredConnections.removeOne(connection); + QSSH_ASSERT_AND_RETURN(wasAquired); + if (m_acquiredConnections.contains(connection)) + return; + + bool doDelete = false; + connection->moveToThread(QCoreApplication::instance()->thread()); + if (m_deprecatedConnections.removeOne(connection) + || connection->state() != SshConnection::Connected) { + doDelete = true; + } else { + QSSH_ASSERT_AND_RETURN(!m_unacquiredConnections.contains(UnaquiredConnection(connection))); + + // It can happen that two or more connections with the same parameters were acquired + // if the clients were running in different threads. Only keep one of them in + // such a case. + bool haveConnection = false; + foreach (const UnaquiredConnection &c, m_unacquiredConnections) { + if (c.connection->connectionParameters() == connection->connectionParameters()) { + haveConnection = true; + break; + } + } + if (!haveConnection) { + connection->closeAllChannels(); // Clean up after neglectful clients. + m_unacquiredConnections.append(UnaquiredConnection(connection)); + } else { + doDelete = true; + } + } + + if (doDelete) { + disconnect(connection, 0, this, 0); + m_deprecatedConnections.removeAll(connection); + connection->deleteLater(); + } + } + + void forceNewConnection(const SshConnectionParameters &sshParams) + { + QMutexLocker locker(&m_listMutex); + + for (int i = 0; i < m_unacquiredConnections.count(); ++i) { + SshConnection * const connection = m_unacquiredConnections.at(i).connection; + if (connection->connectionParameters() == sshParams) { + disconnect(connection, 0, this, 0); + delete connection; + m_unacquiredConnections.removeAt(i); + break; + } + } + + foreach (SshConnection * const connection, m_acquiredConnections) { + if (connection->connectionParameters() == sshParams) { + if (!m_deprecatedConnections.contains(connection)) + m_deprecatedConnections.append(connection); + } + } + } + +private: + Q_INVOKABLE void switchToCallerThread(SshConnection *connection, QObject *threadObj) + { + connection->moveToThread(qobject_cast(threadObj)); + } + + void cleanup() + { + QMutexLocker locker(&m_listMutex); + + SshConnection *currentConnection = qobject_cast(sender()); + if (!currentConnection) + return; + + if (m_unacquiredConnections.removeOne(UnaquiredConnection(currentConnection))) { + disconnect(currentConnection, 0, this, 0); + currentConnection->deleteLater(); + } + } + + void removeInactiveConnections() + { + QMutexLocker locker(&m_listMutex); + for (int i = m_unacquiredConnections.count() - 1; i >= 0; --i) { + UnaquiredConnection &c = m_unacquiredConnections[i]; + if (c.scheduledForRemoval) { + disconnect(c.connection, 0, this, 0); + c.connection->deleteLater(); + m_unacquiredConnections.removeAt(i); + } else { + c.scheduledForRemoval = true; + } + } + } + +private: + // We expect the number of concurrently open connections to be small. + // If that turns out to not be the case, we can still use a data + // structure with faster access. + QList m_unacquiredConnections; + + // Can contain the same connection more than once; this acts as a reference count. + QList m_acquiredConnections; + + QList m_deprecatedConnections; + QMutex m_listMutex; + QTimer m_removalTimer; +}; + +} // namespace Internal + +static QMutex instanceMutex; + +static Internal::SshConnectionManager &instance() +{ + static Internal::SshConnectionManager manager; + return manager; +} + +SshConnection *acquireConnection(const SshConnectionParameters &sshParams) +{ + QMutexLocker locker(&instanceMutex); + return instance().acquireConnection(sshParams); +} + +void releaseConnection(SshConnection *connection) +{ + QMutexLocker locker(&instanceMutex); + instance().releaseConnection(connection); +} + +void forceNewConnection(const SshConnectionParameters &sshParams) +{ + QMutexLocker locker(&instanceMutex); + instance().forceNewConnection(sshParams); +} + +} // namespace QSsh + +#include "sshconnectionmanager.moc" diff --git a/client/3rd/QtSsh/src/ssh/sshconnectionmanager.h b/client/3rd/QtSsh/src/ssh/sshconnectionmanager.h new file mode 100644 index 00000000..87d6c501 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshconnectionmanager.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +namespace QSsh { + +class SshConnection; +class SshConnectionParameters; + +QSSH_EXPORT SshConnection *acquireConnection(const SshConnectionParameters &sshParams); +QSSH_EXPORT void releaseConnection(SshConnection *connection); + +// Make sure the next acquireConnection with the given parameters will return a new connection. +QSSH_EXPORT void forceNewConnection(const SshConnectionParameters &sshParams); + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshcryptofacility.cpp b/client/3rd/QtSsh/src/ssh/sshcryptofacility.cpp new file mode 100644 index 00000000..7156fd80 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshcryptofacility.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshcryptofacility_p.h" + +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshexception_p.h" +#include "sshkeyexchange_p.h" +#include "sshkeypasswordretriever_p.h" +#include "sshlogging_p.h" +#include "sshpacket_p.h" + +#include + +#include +#include + +#include + +using namespace Botan; + +namespace QSsh { +namespace Internal { + +SshAbstractCryptoFacility::SshAbstractCryptoFacility() + : m_cipherBlockSize(0), m_macLength(0) +{ +} + +SshAbstractCryptoFacility::~SshAbstractCryptoFacility() {} + +void SshAbstractCryptoFacility::clearKeys() +{ + m_cipherBlockSize = 0; + m_macLength = 0; + m_sessionId.clear(); + m_pipe.reset(0); + m_hMac.reset(0); +} + +SshAbstractCryptoFacility::Mode SshAbstractCryptoFacility::getMode(const QByteArray &algoName) +{ + if (algoName.endsWith("-ctr")) + return CtrMode; + if (algoName.endsWith("-cbc")) + return CbcMode; + throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"") + .arg(QString::fromLatin1(algoName))); +} + +void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) +{ + checkInvariant(); + + if (m_sessionId.isEmpty()) + m_sessionId = kex.h(); + Algorithm_Factory &af = global_state().algorithm_factory(); + const QByteArray &rfcCryptAlgoName = cryptAlgoName(kex); + BlockCipher * const cipher + = af.prototype_block_cipher(botanCryptAlgoName(rfcCryptAlgoName))->clone(); + + m_cipherBlockSize = static_cast(cipher->block_size()); + const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize); + const InitializationVector iv(convertByteArray(ivData), m_cipherBlockSize); + + const quint32 keySize = static_cast(cipher->key_spec().maximum_keylength()); + const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize); + SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize); + Keyed_Filter * const cipherMode + = makeCipherMode(cipher, getMode(rfcCryptAlgoName), iv, cryptKey); + m_pipe.reset(new Pipe(cipherMode)); + + m_macLength = botanHMacKeyLen(hMacAlgoName(kex)); + const QByteArray hMacKeyData = generateHash(kex, macChar(), macLength()); + SymmetricKey hMacKey(convertByteArray(hMacKeyData), macLength()); + const HashFunction * const hMacProto + = af.prototype_hash_function(botanHMacAlgoName(hMacAlgoName(kex))); + m_hMac.reset(new HMAC(hMacProto->clone())); + m_hMac->set_key(hMacKey); +} + +void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset, + quint32 dataSize) const +{ + Q_ASSERT(offset + dataSize <= static_cast(data.size())); + checkInvariant(); + + // Session id empty => No key exchange has happened yet. + if (dataSize == 0 || m_sessionId.isEmpty()) + return; + + if (dataSize % cipherBlockSize() != 0) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid packet size"); + } + m_pipe->process_msg(reinterpret_cast(data.constData()) + offset, + dataSize); + // Can't use Pipe::LAST_MESSAGE because of a VC bug. + quint32 bytesRead = static_cast(m_pipe->read( + reinterpret_cast(data.data()) + offset, dataSize, m_pipe->message_count() - 1)); + if (bytesRead != dataSize) { + throw SshClientException(SshInternalError, + QLatin1String("Internal error: Botan::Pipe::read() returned unexpected value")); + } +} + +Keyed_Filter *SshAbstractCryptoFacility::makeCtrCipherMode(BlockCipher *cipher, + const InitializationVector &iv, const SymmetricKey &key) +{ + StreamCipher_Filter * const filter = new StreamCipher_Filter(new CTR_BE(cipher)); + filter->set_key(key); + filter->set_iv(iv); + return filter; +} + +QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data, + quint32 dataSize) const +{ + return m_sessionId.isEmpty() + ? QByteArray() + : convertByteArray(m_hMac->process(reinterpret_cast(data.constData()), + dataSize)); +} + +QByteArray SshAbstractCryptoFacility::generateHash(const SshKeyExchange &kex, + char c, quint32 length) +{ + const QByteArray &k = kex.k(); + const QByteArray &h = kex.h(); + QByteArray data(k); + data.append(h).append(c).append(m_sessionId); + SecureVector key + = kex.hash()->process(convertByteArray(data), data.size()); + while (key.size() < length) { + SecureVector tmpKey; + tmpKey += SecureVector(convertByteArray(k), k.size()); + tmpKey += SecureVector(convertByteArray(h), h.size()); + tmpKey += key; + key += kex.hash()->process(tmpKey); + } + return QByteArray(reinterpret_cast(key.begin()), length); +} + +void SshAbstractCryptoFacility::checkInvariant() const +{ + Q_ASSERT(m_sessionId.isEmpty() == !m_pipe); +} + + +const QByteArray SshEncryptionFacility::PrivKeyFileStartLineRsa("-----BEGIN RSA PRIVATE KEY-----"); +const QByteArray SshEncryptionFacility::PrivKeyFileStartLineDsa("-----BEGIN DSA PRIVATE KEY-----"); +const QByteArray SshEncryptionFacility::PrivKeyFileEndLineRsa("-----END RSA PRIVATE KEY-----"); +const QByteArray SshEncryptionFacility::PrivKeyFileEndLineDsa("-----END DSA PRIVATE KEY-----"); +const QByteArray SshEncryptionFacility::PrivKeyFileStartLineEcdsa("-----BEGIN EC PRIVATE KEY-----"); +const QByteArray SshEncryptionFacility::PrivKeyFileEndLineEcdsa("-----END EC PRIVATE KEY-----"); + +QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const +{ + return kex.encryptionAlgo(); +} + +QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const +{ + return kex.hMacAlgoClientToServer(); +} + +Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, + const InitializationVector &iv, const SymmetricKey &key) +{ + switch (mode) { + case CbcMode: + return new CBC_Encryption(cipher, new Null_Padding, key, iv); + case CtrMode: + return makeCtrCipherMode(cipher, iv, key); + } + return 0; // For dumb compilers. +} + +void SshEncryptionFacility::encrypt(QByteArray &data) const +{ + convert(data, 0, data.size()); +} + +void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFileContents) +{ + if (privKeyFileContents == m_cachedPrivKeyContents) + return; + + m_authKeyAlgoName.clear(); + qCDebug(sshLog, "%s: Key not cached, reading", Q_FUNC_INFO); + QList pubKeyParams; + QList allKeyParams; + QString error1; + QString error2; + if (!createAuthenticationKeyFromPKCS8(privKeyFileContents, pubKeyParams, allKeyParams, error1) + && !createAuthenticationKeyFromOpenSSL(privKeyFileContents, pubKeyParams, allKeyParams, + error2)) { + qCDebug(sshLog, "%s: %s\n\t%s\n", Q_FUNC_INFO, qPrintable(error1), qPrintable(error2)); + throw SshClientException(SshKeyFileError, SSH_TR("Decoding of private key file failed: " + "Format not understood.")); + } + + foreach (const BigInt &b, allKeyParams) { + if (b.is_zero()) { + throw SshClientException(SshKeyFileError, + SSH_TR("Decoding of private key file failed: Invalid zero parameter.")); + } + } + + m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName); + auto * const ecdsaKey = dynamic_cast(m_authKey.data()); + if (ecdsaKey) { + m_authPubKeyBlob += AbstractSshPacket::encodeString(m_authKeyAlgoName.mid(11)); // Without "ecdsa-sha2-" prefix. + m_authPubKeyBlob += AbstractSshPacket::encodeString( + convertByteArray(EC2OSP(ecdsaKey->public_point(), PointGFp::UNCOMPRESSED))); + } else { + foreach (const BigInt &b, pubKeyParams) + m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b); + } + m_cachedPrivKeyContents = privKeyFileContents; +} + +bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams, QString &error) +{ + try { + Pipe pipe; + pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size()); + m_authKey.reset(PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever())); + if (auto * const dsaKey = dynamic_cast(m_authKey.data())) { + m_authKeyAlgoName = SshCapabilities::PubKeyDss; + pubKeyParams << dsaKey->group_p() << dsaKey->group_q() + << dsaKey->group_g() << dsaKey->get_y(); + allKeyParams << pubKeyParams << dsaKey->get_x(); + } else if (auto * const rsaKey = dynamic_cast(m_authKey.data())) { + m_authKeyAlgoName = SshCapabilities::PubKeyRsa; + pubKeyParams << rsaKey->get_e() << rsaKey->get_n(); + allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q() + << rsaKey->get_d(); + } else if (auto * const ecdsaKey = dynamic_cast(m_authKey.data())) { + const BigInt value = ecdsaKey->private_value(); + m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( + static_cast(value.bytes())); + pubKeyParams << ecdsaKey->public_point().get_affine_x() + << ecdsaKey->public_point().get_affine_y(); + allKeyParams << pubKeyParams << value; + } else { + qCWarning(sshLog, "%s: Unexpected code flow, expected success or exception.", + Q_FUNC_INFO); + return false; + } + } catch (const std::exception &ex) { + error = QLatin1String(ex.what()); + return false; + } + + return true; +} + +bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams, QString &error) +{ + try { + bool syntaxOk = true; + QList lines = privKeyFileContents.split('\n'); + while (lines.last().isEmpty()) + lines.removeLast(); + if (lines.count() < 3) { + syntaxOk = false; + } else if (lines.first() == PrivKeyFileStartLineRsa) { + if (lines.last() != PrivKeyFileEndLineRsa) + syntaxOk = false; + else + m_authKeyAlgoName = SshCapabilities::PubKeyRsa; + } else if (lines.first() == PrivKeyFileStartLineDsa) { + if (lines.last() != PrivKeyFileEndLineDsa) + syntaxOk = false; + else + m_authKeyAlgoName = SshCapabilities::PubKeyDss; + } else if (lines.first() == PrivKeyFileStartLineEcdsa) { + if (lines.last() != PrivKeyFileEndLineEcdsa) + syntaxOk = false; + // m_authKeyAlgoName set below, as we don't know the size yet. + } else { + syntaxOk = false; + } + if (!syntaxOk) { + error = SSH_TR("Unexpected format."); + return false; + } + + QByteArray privateKeyBlob; + for (int i = 1; i < lines.size() - 1; ++i) + privateKeyBlob += lines.at(i); + privateKeyBlob = QByteArray::fromBase64(privateKeyBlob); + + BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size()); + BER_Decoder sequence = decoder.start_cons(SEQUENCE); + size_t version; + sequence.decode (version); + const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0; + if (version != expectedVersion) { + error = SSH_TR("Key encoding has version %1, expected %2.") + .arg(version).arg(expectedVersion); + return false; + } + + if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) { + BigInt p, q, g, y, x; + sequence.decode (p).decode (q).decode (g).decode (y).decode (x); + DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x); + m_authKey.reset(dsaKey); + pubKeyParams << p << q << g << y; + allKeyParams << pubKeyParams << x; + } else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) { + BigInt p, q, e, d, n; + sequence.decode(n).decode(e).decode(d).decode(p).decode(q); + RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n); + m_authKey.reset(rsaKey); + pubKeyParams << e << n; + allKeyParams << pubKeyParams << p << q << d; + } else { + BigInt privKey; + sequence.decode_octet_string_bigint(privKey); + m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( + static_cast(privKey.bytes())); + const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName)); + auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey); + m_authKey.reset(key); + pubKeyParams << key->public_point().get_affine_x() + << key->public_point().get_affine_y(); + allKeyParams << pubKeyParams << privKey; + } + + sequence.discard_remaining(); + sequence.verify_end(); + } catch (const std::exception &ex) { + error = QLatin1String(ex.what()); + return false; + } + return true; +} + +QByteArray SshEncryptionFacility::authenticationAlgorithmName() const +{ + Q_ASSERT(m_authKey); + return m_authKeyAlgoName; +} + +QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &data) const +{ + Q_ASSERT(m_authKey); + + QScopedPointer signer(new PK_Signer(*m_authKey, + botanEmsaAlgoName(m_authKeyAlgoName))); + QByteArray dataToSign = AbstractSshPacket::encodeString(sessionId()) + data; + QByteArray signature + = convertByteArray(signer->sign_message(convertByteArray(dataToSign), + dataToSign.size(), m_rng)); + if (m_authKeyAlgoName.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) { + // The Botan output is not quite in the format that SSH defines. + const int halfSize = signature.count() / 2; + const BigInt r = BigInt::decode(convertByteArray(signature), halfSize); + const BigInt s = BigInt::decode(convertByteArray(signature.mid(halfSize)), halfSize); + signature = AbstractSshPacket::encodeMpInt(r) + AbstractSshPacket::encodeMpInt(s); + } + return AbstractSshPacket::encodeString(m_authKeyAlgoName) + + AbstractSshPacket::encodeString(signature); +} + +QByteArray SshEncryptionFacility::getRandomNumbers(int count) const +{ + QByteArray data; + data.resize(count); + m_rng.randomize(convertByteArray(data), count); + return data; +} + +SshEncryptionFacility::~SshEncryptionFacility() {} + + +QByteArray SshDecryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const +{ + return kex.decryptionAlgo(); +} + +QByteArray SshDecryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const +{ + return kex.hMacAlgoServerToClient(); +} + +Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, const InitializationVector &iv, + const SymmetricKey &key) +{ + switch (mode) { + case CbcMode: + return new CBC_Decryption(cipher, new Null_Padding, key, iv); + case CtrMode: + return makeCtrCipherMode(cipher, iv, key); + } + return 0; // For dumb compilers. +} + +void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset, + quint32 dataSize) const +{ + convert(data, offset, dataSize); + qCDebug(sshLog, "Decrypted data:"); + const char * const start = data.constData() + offset; + const char * const end = start + dataSize; + for (const char *c = start; c < end; ++c) + qCDebug(sshLog, ) << "'" << *c << "' (0x" << (static_cast(*c) & 0xff) << ")"; +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshcryptofacility_p.h b/client/3rd/QtSsh/src/ssh/sshcryptofacility_p.h new file mode 100644 index 00000000..db008207 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshcryptofacility_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +namespace QSsh { +namespace Internal { + +class SshKeyExchange; + +class SshAbstractCryptoFacility +{ +public: + virtual ~SshAbstractCryptoFacility(); + + void clearKeys(); + void recreateKeys(const SshKeyExchange &kex); + QByteArray generateMac(const QByteArray &data, quint32 dataSize) const; + quint32 cipherBlockSize() const { return m_cipherBlockSize; } + quint32 macLength() const { return m_macLength; } + +protected: + enum Mode { CbcMode, CtrMode }; + + SshAbstractCryptoFacility(); + void convert(QByteArray &data, quint32 offset, quint32 dataSize) const; + QByteArray sessionId() const { return m_sessionId; } + Botan::Keyed_Filter *makeCtrCipherMode(Botan::BlockCipher *cipher, + const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); + +private: + SshAbstractCryptoFacility(const SshAbstractCryptoFacility &); + SshAbstractCryptoFacility &operator=(const SshAbstractCryptoFacility &); + + virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0; + virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0; + virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key) = 0; + virtual char ivChar() const = 0; + virtual char keyChar() const = 0; + virtual char macChar() const = 0; + + QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length); + void checkInvariant() const; + static Mode getMode(const QByteArray &algoName); + + QByteArray m_sessionId; + QScopedPointer m_pipe; + QScopedPointer m_hMac; + quint32 m_cipherBlockSize; + quint32 m_macLength; +}; + +class SshEncryptionFacility : public SshAbstractCryptoFacility +{ +public: + void encrypt(QByteArray &data) const; + + void createAuthenticationKey(const QByteArray &privKeyFileContents); + QByteArray authenticationAlgorithmName() const; + QByteArray authenticationPublicKey() const { return m_authPubKeyBlob; } + QByteArray authenticationKeySignature(const QByteArray &data) const; + QByteArray getRandomNumbers(int count) const; + + ~SshEncryptionFacility(); + +private: + virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const; + virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const; + virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); + virtual char ivChar() const { return 'A'; } + virtual char keyChar() const { return 'C'; } + virtual char macChar() const { return 'E'; } + + bool createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams, QString &error); + bool createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams, QString &error); + + static const QByteArray PrivKeyFileStartLineRsa; + static const QByteArray PrivKeyFileStartLineDsa; + static const QByteArray PrivKeyFileEndLineRsa; + static const QByteArray PrivKeyFileEndLineDsa; + static const QByteArray PrivKeyFileStartLineEcdsa; + static const QByteArray PrivKeyFileEndLineEcdsa; + + QByteArray m_authKeyAlgoName; + QByteArray m_authPubKeyBlob; + QByteArray m_cachedPrivKeyContents; + QScopedPointer m_authKey; + mutable Botan::AutoSeeded_RNG m_rng; +}; + +class SshDecryptionFacility : public SshAbstractCryptoFacility +{ +public: + void decrypt(QByteArray &data, quint32 offset, quint32 dataSize) const; + +private: + virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const; + virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const; + virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); + virtual char ivChar() const { return 'B'; } + virtual char keyChar() const { return 'D'; } + virtual char macChar() const { return 'F'; } +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.cpp b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.cpp new file mode 100644 index 00000000..9700bd99 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshdirecttcpiptunnel.h" +#include "sshdirecttcpiptunnel_p.h" + +#include "sshincomingpacket_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +#include + +namespace QSsh { +namespace Internal { + +SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId, + const QString &originatingHost, quint16 originatingPort, const QString &remoteHost, + quint16 remotePort, SshSendFacility &sendFacility) + : SshTcpIpTunnelPrivate(channelId, sendFacility), + m_originatingHost(originatingHost), + m_originatingPort(originatingPort), + m_remoteHost(remoteHost), + m_remotePort(remotePort) +{ +} + +void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal() +{ + emit initialized(); +} + +} // namespace Internal + +using namespace Internal; + +SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort, + SshSendFacility &sendFacility) + : d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost, + remotePort, sendFacility)) +{ + d->init(this); + connect(d, &SshDirectTcpIpTunnelPrivate::initialized, + this, &SshDirectTcpIpTunnel::initialized, Qt::QueuedConnection); +} + +SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel() +{ + delete d; +} + +bool SshDirectTcpIpTunnel::atEnd() const +{ + return QIODevice::atEnd() && d->m_data.isEmpty(); +} + +qint64 SshDirectTcpIpTunnel::bytesAvailable() const +{ + return QIODevice::bytesAvailable() + d->m_data.count(); +} + +bool SshDirectTcpIpTunnel::canReadLine() const +{ + return QIODevice::canReadLine() || d->m_data.contains('\n'); +} + +void SshDirectTcpIpTunnel::close() +{ + d->closeChannel(); + QIODevice::close(); +} + +void SshDirectTcpIpTunnel::initialize() +{ + QSSH_ASSERT_AND_RETURN(d->channelState() == AbstractSshChannel::Inactive); + + try { + QIODevice::open(QIODevice::ReadWrite); + d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), d->initialWindowSize(), + d->maxPacketSize(), d->m_remoteHost.toUtf8(), d->m_remotePort, + d->m_originatingHost.toUtf8(), d->m_originatingPort); + d->setChannelState(AbstractSshChannel::SessionRequested); + d->m_timeoutTimer.start(d->ReplyTimeout); + } catch (const std::exception &e) { // Won't happen, but let's play it safe. + qCWarning(sshLog, "Botan error: %s", e.what()); + d->closeChannel(); + } +} + +qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen) +{ + return d->readData(data, maxlen); +} + +qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len) +{ + return d->writeData(data, len); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.h b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.h new file mode 100644 index 00000000..5d23f1cf --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include +#include + +namespace QSsh { + +namespace Internal { +class SshChannelManager; +class SshDirectTcpIpTunnelPrivate; +class SshSendFacility; +class SshTcpIpTunnelPrivate; +} // namespace Internal + +class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice +{ + Q_OBJECT + + friend class Internal::SshChannelManager; + friend class Internal::SshTcpIpTunnelPrivate; + +public: + typedef QSharedPointer Ptr; + + ~SshDirectTcpIpTunnel(); + + // QIODevice stuff + bool atEnd() const; + qint64 bytesAvailable() const; + bool canReadLine() const; + void close(); + bool isSequential() const { return true; } + + void initialize(); + +signals: + void initialized(); + void error(const QString &reason); + +private: + SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort, + Internal::SshSendFacility &sendFacility); + + // QIODevice stuff + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + Internal::SshDirectTcpIpTunnelPrivate * const d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel_p.h b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel_p.h new file mode 100644 index 00000000..a2a4ac1c --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshdirecttcpiptunnel_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshtcpiptunnel_p.h" + +namespace QSsh { +class SshDirectTcpIpTunnel; + +namespace Internal { + +class SshDirectTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate +{ + Q_OBJECT + + friend class QSsh::SshDirectTcpIpTunnel; + +public: + explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, const QString &originatingHost, + quint16 originatingPort, const QString &remoteHost, quint16 remotePort, + SshSendFacility &sendFacility); + +signals: + void initialized(); + +private: + void handleOpenSuccessInternal(); + + const QString m_originatingHost; + const quint16 m_originatingPort; + const QString m_remoteHost; + const quint16 m_remotePort; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/ssherrors.h b/client/3rd/QtSsh/src/ssh/ssherrors.h new file mode 100644 index 00000000..4c85e071 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/ssherrors.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once +#define SSHERRORS_P_H + +namespace QSsh { + +enum SshError { + SshNoError, SshSocketError, SshTimeoutError, SshProtocolError, + SshHostKeyError, SshKeyFileError, SshAuthenticationError, + SshClosedByServerError, SshInternalError +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshexception_p.h b/client/3rd/QtSsh/src/ssh/sshexception_p.h new file mode 100644 index 00000000..b51ce4b0 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshexception_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssherrors.h" + +#include +#include +#include + +namespace QSsh { +namespace Internal { + +enum SshErrorCode { + SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1, + SSH_DISCONNECT_PROTOCOL_ERROR = 2, + SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3, + SSH_DISCONNECT_RESERVED = 4, + SSH_DISCONNECT_MAC_ERROR = 5, + SSH_DISCONNECT_COMPRESSION_ERROR = 6, + SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7, + SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8, + SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9, + SSH_DISCONNECT_CONNECTION_LOST = 10, + SSH_DISCONNECT_BY_APPLICATION = 11, + SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12, + SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13, + SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14, + SSH_DISCONNECT_ILLEGAL_USER_NAME = 15 +}; + +#define SSH_TR(string) QCoreApplication::translate("SshConnection", string) + +#define SSH_SERVER_EXCEPTION(error, errorString) \ + SshServerException((error), (errorString), SSH_TR(errorString)) + +struct SshServerException +{ + SshServerException(SshErrorCode error, const QByteArray &errorStringServer, + const QString &errorStringUser) + : error(error), errorStringServer(errorStringServer), + errorStringUser(errorStringUser) {} + + const SshErrorCode error; + const QByteArray errorStringServer; + const QString errorStringUser; +}; + +struct SshClientException +{ + SshClientException(SshError error, const QString &errorString) + : error(error), errorString(errorString) {} + + const SshError error; + const QString errorString; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.cpp b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.cpp new file mode 100644 index 00000000..22442f7c --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshforwardedtcpiptunnel.h" +#include "sshforwardedtcpiptunnel_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +namespace QSsh { + +namespace Internal { +SshForwardedTcpIpTunnelPrivate::SshForwardedTcpIpTunnelPrivate(quint32 channelId, + SshSendFacility &sendFacility) : + SshTcpIpTunnelPrivate(channelId, sendFacility) +{ + setChannelState(SessionRequested); +} + +void SshForwardedTcpIpTunnelPrivate::handleOpenSuccessInternal() +{ + QSSH_ASSERT_AND_RETURN(channelState() == AbstractSshChannel::SessionEstablished); + + try { + m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(), + initialWindowSize(), maxPacketSize()); + } catch (const std::exception &e) { // Won't happen, but let's play it safe. + qCWarning(sshLog, "Botan error: %s", e.what()); + closeChannel(); + } +} + +} // namespace Internal + +using namespace Internal; + +SshForwardedTcpIpTunnel::SshForwardedTcpIpTunnel(quint32 channelId, SshSendFacility &sendFacility) : + d(new SshForwardedTcpIpTunnelPrivate(channelId, sendFacility)) +{ + d->init(this); +} + +SshForwardedTcpIpTunnel::~SshForwardedTcpIpTunnel() +{ + delete d; +} + +bool SshForwardedTcpIpTunnel::atEnd() const +{ + return QIODevice::atEnd() && d->m_data.isEmpty(); +} + +qint64 SshForwardedTcpIpTunnel::bytesAvailable() const +{ + return QIODevice::bytesAvailable() + d->m_data.count(); +} + +bool SshForwardedTcpIpTunnel::canReadLine() const +{ + return QIODevice::canReadLine() || d->m_data.contains('\n'); +} + +void SshForwardedTcpIpTunnel::close() +{ + d->closeChannel(); + QIODevice::close(); +} + +qint64 SshForwardedTcpIpTunnel::readData(char *data, qint64 maxlen) +{ + return d->readData(data, maxlen); +} + +qint64 SshForwardedTcpIpTunnel::writeData(const char *data, qint64 len) +{ + return d->writeData(data, len); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.h b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.h new file mode 100644 index 00000000..cb33c304 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#pragma once + +#include "ssh_global.h" +#include +#include + +namespace QSsh { + +namespace Internal { +class SshChannelManager; +class SshForwardedTcpIpTunnelPrivate; +class SshSendFacility; +class SshTcpIpTunnelPrivate; +} // namespace Internal + +class QSSH_EXPORT SshForwardedTcpIpTunnel : public QIODevice +{ + Q_OBJECT + friend class Internal::SshChannelManager; + friend class Internal::SshTcpIpTunnelPrivate; + +public: + typedef QSharedPointer Ptr; + ~SshForwardedTcpIpTunnel() override; + + // QIODevice stuff + bool atEnd() const override; + qint64 bytesAvailable() const override; + bool canReadLine() const override; + void close() override; + bool isSequential() const override { return true; } + +signals: + void error(const QString &reason); + +private: + SshForwardedTcpIpTunnel(quint32 channelId, Internal::SshSendFacility &sendFacility); + + // QIODevice stuff + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + + Internal::SshForwardedTcpIpTunnelPrivate * const d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel_p.h b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel_p.h new file mode 100644 index 00000000..7b5043da --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshforwardedtcpiptunnel_p.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshforwardedtcpiptunnel.h" +#include "sshtcpiptunnel_p.h" + +namespace QSsh { +namespace Internal { + +class SshForwardedTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate +{ + Q_OBJECT + friend class QSsh::SshForwardedTcpIpTunnel; +public: + SshForwardedTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility); + void handleOpenSuccessInternal() override; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.cpp b/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.cpp new file mode 100644 index 00000000..ebf1c643 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshhostkeydatabase.h" + +#include "sshlogging_p.h" + +#include +#include +#include +#include +#include +#include + +namespace QSsh { + +class SshHostKeyDatabase::SshHostKeyDatabasePrivate +{ +public: + QHash hostKeys; +}; + +SshHostKeyDatabase::SshHostKeyDatabase() : d(new SshHostKeyDatabasePrivate) +{ +} + +SshHostKeyDatabase::~SshHostKeyDatabase() +{ + delete d; +} + +bool SshHostKeyDatabase::load(const QString &filePath, QString *error) +{ + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + if (error) { + *error = QCoreApplication::translate("QSsh::Ssh", + "Failed to open key file \"%1\" for reading: %2") + .arg(QDir::toNativeSeparators(filePath), file.errorString()); + } + return false; + } + + d->hostKeys.clear(); + const QByteArray content = file.readAll().trimmed(); + if (content.isEmpty()) + return true; + foreach (const QByteArray &line, content.split('\n')) { + const QList &lineData = line.trimmed().split(' '); + if (lineData.count() != 2) { + qCDebug(Internal::sshLog, "Unexpected line \"%s\" in file \"%s\".", line.constData(), + qPrintable(filePath)); + continue; + } + d->hostKeys.insert(QString::fromUtf8(lineData.first()), + QByteArray::fromHex(lineData.last())); + } + + return true; +} + +bool SshHostKeyDatabase::store(const QString &filePath, QString *error) const +{ + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly)) { + if (error) { + *error = QCoreApplication::translate("QSsh::Ssh", + "Failed to open key file \"%1\" for writing: %2") + .arg(QDir::toNativeSeparators(filePath), file.errorString()); + } + return false; + } + + file.resize(0); + for (auto it = d->hostKeys.constBegin(); it != d->hostKeys.constEnd(); ++it) + file.write(it.key().toUtf8() + ' ' + it.value().toHex() + '\n'); + return true; +} + +SshHostKeyDatabase::KeyLookupResult SshHostKeyDatabase::matchHostKey(const QString &hostName, + const QByteArray &key) const +{ + auto it = d->hostKeys.constFind(hostName); + if (it == d->hostKeys.constEnd()) + return KeyLookupNoMatch; + if (it.value() == key) + return KeyLookupMatch; + return KeyLookupMismatch; +} + +void SshHostKeyDatabase::insertHostKey(const QString &hostName, const QByteArray &key) +{ + d->hostKeys.insert(hostName, key); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.h b/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.h new file mode 100644 index 00000000..bd58ab86 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshhostkeydatabase.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +class QString; +QT_END_NAMESPACE + +namespace QSsh { +class SshHostKeyDatabase; +typedef QSharedPointer SshHostKeyDatabasePtr; + +class QSSH_EXPORT SshHostKeyDatabase +{ + friend class QSharedPointer; // To give create() access to our constructor. + +public: + enum KeyLookupResult { + KeyLookupMatch, + KeyLookupNoMatch, + KeyLookupMismatch + }; + + ~SshHostKeyDatabase(); + + bool load(const QString &filePath, QString *error = 0); + bool store(const QString &filePath, QString *error = 0) const; + KeyLookupResult matchHostKey(const QString &hostName, const QByteArray &key) const; + void insertHostKey(const QString &hostName, const QByteArray &key); + +private: + SshHostKeyDatabase(); + + class SshHostKeyDatabasePrivate; + SshHostKeyDatabasePrivate * const d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshincomingpacket.cpp b/client/3rd/QtSsh/src/ssh/sshincomingpacket.cpp new file mode 100644 index 00000000..5bb83914 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshincomingpacket.cpp @@ -0,0 +1,552 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshincomingpacket_p.h" + +#include "ssh_global.h" +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshlogging_p.h" + +namespace QSsh { +namespace Internal { + +const QByteArray SshIncomingPacket::ExitStatusType("exit-status"); +const QByteArray SshIncomingPacket::ExitSignalType("exit-signal"); +const QByteArray SshIncomingPacket::ForwardedTcpIpType("forwarded-tcpip"); + +SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { } + +quint32 SshIncomingPacket::cipherBlockSize() const +{ + return qMax(m_decrypter.cipherBlockSize(), 8U); +} + +quint32 SshIncomingPacket::macLength() const +{ + return m_decrypter.macLength(); +} + +void SshIncomingPacket::recreateKeys(const SshKeyExchange &keyExchange) +{ + m_decrypter.recreateKeys(keyExchange); +} + +void SshIncomingPacket::reset() +{ + clear(); + m_serverSeqNr = 0; + m_decrypter.clearKeys(); +} + +void SshIncomingPacket::consumeData(QByteArray &newData) +{ + qCDebug(sshLog, "%s: current data size = %d, new data size = %d", + Q_FUNC_INFO, m_data.size(), newData.size()); + + if (isComplete() || newData.isEmpty()) + return; + + /* + * Until we have reached the minimum packet size, we cannot decrypt the + * length field. + */ + const quint32 minSize = minPacketSize(); + if (currentDataSize() < minSize) { + const int bytesToTake + = qMin(minSize - currentDataSize(), newData.size()); + moveFirstBytes(m_data, newData, bytesToTake); + qCDebug(sshLog, "Took %d bytes from new data", bytesToTake); + if (currentDataSize() < minSize) + return; + } + + if (4 + length() + macLength() < currentDataSize()) + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server sent invalid packet."); + + const int bytesToTake + = qMin(length() + 4 + macLength() - currentDataSize(), + newData.size()); + moveFirstBytes(m_data, newData, bytesToTake); + qCDebug(sshLog, "Took %d bytes from new data", bytesToTake); + if (isComplete()) { + qCDebug(sshLog, "Message complete. Overall size: %u, payload size: %u", + m_data.size(), m_length - paddingLength() - 1); + decrypt(); + ++m_serverSeqNr; + } +} + +void SshIncomingPacket::decrypt() +{ + Q_ASSERT(isComplete()); + const quint32 netDataLength = length() + 4; + m_decrypter.decrypt(m_data, cipherBlockSize(), + netDataLength - cipherBlockSize()); + const QByteArray &mac = m_data.mid(netDataLength, macLength()); + if (mac != generateMac(m_decrypter, m_serverSeqNr)) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_MAC_ERROR, + "Message authentication failed."); + } +} + +void SshIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source, + int n) +{ + target.append(source.left(n)); + source.remove(0, n); +} + +SshKeyExchangeInit SshIncomingPacket::extractKeyExchangeInitData() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_KEXINIT); + + SshKeyExchangeInit exchangeData; + try { + quint32 offset = TypeOffset + 1; + std::memcpy(exchangeData.cookie, &m_data.constData()[offset], + sizeof exchangeData.cookie); + offset += sizeof exchangeData.cookie; + exchangeData.keyAlgorithms + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.serverHostKeyAlgorithms + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.encryptionAlgorithmsClientToServer + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.encryptionAlgorithmsServerToClient + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.macAlgorithmsClientToServer + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.macAlgorithmsServerToClient + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.compressionAlgorithmsClientToServer + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.compressionAlgorithmsServerToClient + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.languagesClientToServer + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.languagesServerToClient + = SshPacketParser::asNameList(m_data, &offset); + exchangeData.firstKexPacketFollows + = SshPacketParser::asBool(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet."); + } + return exchangeData; +} + +static void getHostKeySpecificReplyData(SshKeyExchangeReply &replyData, + const QByteArray &hostKeyAlgo, const QByteArray &input) +{ + quint32 offset = 0; + if (hostKeyAlgo == SshCapabilities::PubKeyDss || hostKeyAlgo == SshCapabilities::PubKeyRsa) { + // DSS: p and q, RSA: e and n + replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset); + replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset); + + // g and y + if (hostKeyAlgo == SshCapabilities::PubKeyDss) { + replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset); + replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset); + } + } else { + QSSH_ASSERT_AND_RETURN(hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix)); + if (SshPacketParser::asString(input, &offset) + != hostKeyAlgo.mid(11)) { // Without "ecdsa-sha2-" prefix. + throw SshPacketParseException(); + } + replyData.q = SshPacketParser::asString(input, &offset); + } +} + +static QByteArray &padToWidth(QByteArray &data, int targetWidth) +{ + return data.prepend(QByteArray(targetWidth - data.count(), 0)); +} + +SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &kexAlgo, + const QByteArray &hostKeyAlgo) const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY); + + try { + SshKeyExchangeReply replyData; + quint32 topLevelOffset = TypeOffset + 1; + replyData.k_s = SshPacketParser::asString(m_data, &topLevelOffset); + quint32 k_sOffset = 0; + if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != hostKeyAlgo) + throw SshPacketParseException(); + getHostKeySpecificReplyData(replyData, hostKeyAlgo, replyData.k_s.mid(k_sOffset)); + + if (kexAlgo == SshCapabilities::DiffieHellmanGroup1Sha1) { + replyData.f = SshPacketParser::asBigInt(m_data, &topLevelOffset); + } else { + QSSH_ASSERT_AND_RETURN_VALUE(kexAlgo.startsWith(SshCapabilities::EcdhKexNamePrefix), + SshKeyExchangeReply()); + replyData.q_s = SshPacketParser::asString(m_data, &topLevelOffset); + } + const QByteArray fullSignature = SshPacketParser::asString(m_data, &topLevelOffset); + quint32 sigOffset = 0; + if (SshPacketParser::asString(fullSignature, &sigOffset) != hostKeyAlgo) + throw SshPacketParseException(); + replyData.signatureBlob = SshPacketParser::asString(fullSignature, &sigOffset); + if (hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) { + // Botan's PK_Verifier wants the signature in this format. + quint32 blobOffset = 0; + const Botan::BigInt r = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset); + const Botan::BigInt s = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset); + const int width = SshCapabilities::ecdsaIntegerWidthInBytes(hostKeyAlgo); + QByteArray encodedR = convertByteArray(Botan::BigInt::encode(r)); + replyData.signatureBlob = padToWidth(encodedR, width); + QByteArray encodedS = convertByteArray(Botan::BigInt::encode(s)); + replyData.signatureBlob += padToWidth(encodedS, width); + } + replyData.k_s.prepend(m_data.mid(TypeOffset + 1, 4)); + return replyData; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Key exchange failed: " + "Server sent invalid key exchange reply packet."); + } +} + +SshDisconnect SshIncomingPacket::extractDisconnect() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_DISCONNECT); + + SshDisconnect msg; + try { + quint32 offset = TypeOffset + 1; + msg.reasonCode = SshPacketParser::asUint32(m_data, &offset); + msg.description = SshPacketParser::asUserString(m_data, &offset); + msg.language = SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_DISCONNECT."); + } + + return msg; +} + +SshUserAuthBanner SshIncomingPacket::extractUserAuthBanner() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_USERAUTH_BANNER); + + try { + SshUserAuthBanner msg; + quint32 offset = TypeOffset + 1; + msg.message = SshPacketParser::asUserString(m_data, &offset); + msg.language = SshPacketParser::asString(m_data, &offset); + return msg; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_USERAUTH_BANNER."); + } +} + +SshUserAuthInfoRequestPacket SshIncomingPacket::extractUserAuthInfoRequest() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_USERAUTH_INFO_REQUEST); + + try { + SshUserAuthInfoRequestPacket msg; + quint32 offset = TypeOffset + 1; + msg.name = SshPacketParser::asUserString(m_data, &offset); + msg.instruction = SshPacketParser::asUserString(m_data, &offset); + msg.languageTag = SshPacketParser::asString(m_data, &offset); + const quint32 promptCount = SshPacketParser::asUint32(m_data, &offset); + msg.prompts.reserve(promptCount); + msg.echos.reserve(promptCount); + for (quint32 i = 0; i < promptCount; ++i) { + msg.prompts << SshPacketParser::asUserString(m_data, &offset); + msg.echos << SshPacketParser::asBool(m_data, &offset); + } + return msg; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_USERAUTH_INFO_REQUEST."); + } +} + +SshDebug SshIncomingPacket::extractDebug() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_DEBUG); + + try { + SshDebug msg; + quint32 offset = TypeOffset + 1; + msg.display = SshPacketParser::asBool(m_data, &offset); + msg.message = SshPacketParser::asUserString(m_data, &offset); + msg.language = SshPacketParser::asString(m_data, &offset); + return msg; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_DEBUG."); + } +} + +SshRequestSuccess SshIncomingPacket::extractRequestSuccess() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_REQUEST_SUCCESS); + + try { + SshRequestSuccess msg; + quint32 offset = TypeOffset + 1; + msg.bindPort = SshPacketParser::asUint32(m_data, &offset); + return msg; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_REQUEST_SUCCESS."); + } +} + +SshUnimplemented SshIncomingPacket::extractUnimplemented() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_UNIMPLEMENTED); + + try { + SshUnimplemented msg; + quint32 offset = TypeOffset + 1; + msg.invalidMsgSeqNr = SshPacketParser::asUint32(m_data, &offset); + return msg; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_UNIMPLEMENTED."); + } +} + +SshChannelOpen SshIncomingPacket::extractChannelOpen() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN); + + SshChannelOpen open; + try { + quint32 offset = TypeOffset + 1; + QByteArray type = SshPacketParser::asString(m_data, &offset); + open.remoteChannel = SshPacketParser::asUint32(m_data, &offset); + open.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset); + open.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset); + if (type == ForwardedTcpIpType) { + open.remoteAddress = SshPacketParser::asString(m_data, &offset); + open.remotePort = SshPacketParser::asUint32(m_data, &offset); + } else { + open.remotePort = 0; + } + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server sent invalid SSH_MSG_CHANNEL_OPEN packet."); + } + return open; +} + +SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_FAILURE); + + SshChannelOpenFailure openFailure; + try { + quint32 offset = TypeOffset + 1; + openFailure.localChannel = SshPacketParser::asUint32(m_data, &offset); + openFailure.reasonCode = SshPacketParser::asUint32(m_data, &offset); + openFailure.reasonString = QString::fromLocal8Bit(SshPacketParser::asString(m_data, &offset)); + openFailure.language = SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server sent invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet."); + } + return openFailure; +} + +SshChannelOpenConfirmation SshIncomingPacket::extractChannelOpenConfirmation() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + + SshChannelOpenConfirmation confirmation; + try { + quint32 offset = TypeOffset + 1; + confirmation.localChannel = SshPacketParser::asUint32(m_data, &offset); + confirmation.remoteChannel = SshPacketParser::asUint32(m_data, &offset); + confirmation.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset); + confirmation.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server sent invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet."); + } + return confirmation; +} + +SshChannelWindowAdjust SshIncomingPacket::extractWindowAdjust() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_WINDOW_ADJUST); + + SshChannelWindowAdjust adjust; + try { + quint32 offset = TypeOffset + 1; + adjust.localChannel = SshPacketParser::asUint32(m_data, &offset); + adjust.bytesToAdd = SshPacketParser::asUint32(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_WINDOW_ADJUST packet."); + } + return adjust; +} + +SshChannelData SshIncomingPacket::extractChannelData() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_DATA); + + SshChannelData data; + try { + quint32 offset = TypeOffset + 1; + data.localChannel = SshPacketParser::asUint32(m_data, &offset); + data.data = SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_DATA packet."); + } + return data; +} + +SshChannelExtendedData SshIncomingPacket::extractChannelExtendedData() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_EXTENDED_DATA); + + SshChannelExtendedData data; + try { + quint32 offset = TypeOffset + 1; + data.localChannel = SshPacketParser::asUint32(m_data, &offset); + data.type = SshPacketParser::asUint32(m_data, &offset); + data.data = SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_EXTENDED_DATA packet."); + } + return data; +} + +SshChannelExitStatus SshIncomingPacket::extractChannelExitStatus() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST); + + SshChannelExitStatus exitStatus; + try { + quint32 offset = TypeOffset + 1; + exitStatus.localChannel = SshPacketParser::asUint32(m_data, &offset); + const QByteArray &type = SshPacketParser::asString(m_data, &offset); + Q_ASSERT(type == ExitStatusType); + Q_UNUSED(type); + if (SshPacketParser::asBool(m_data, &offset)) + throw SshPacketParseException(); + exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid exit-status packet."); + } + return exitStatus; +} + +SshChannelExitSignal SshIncomingPacket::extractChannelExitSignal() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST); + + SshChannelExitSignal exitSignal; + try { + quint32 offset = TypeOffset + 1; + exitSignal.localChannel = SshPacketParser::asUint32(m_data, &offset); + const QByteArray &type = SshPacketParser::asString(m_data, &offset); + Q_ASSERT(type == ExitSignalType); + Q_UNUSED(type); + if (SshPacketParser::asBool(m_data, &offset)) + throw SshPacketParseException(); + exitSignal.signal = SshPacketParser::asString(m_data, &offset); + exitSignal.coreDumped = SshPacketParser::asBool(m_data, &offset); + exitSignal.error = SshPacketParser::asUserString(m_data, &offset); + exitSignal.language = SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid exit-signal packet."); + } + return exitSignal; +} + +quint32 SshIncomingPacket::extractRecipientChannel() const +{ + Q_ASSERT(isComplete()); + + try { + quint32 offset = TypeOffset + 1; + return SshPacketParser::asUint32(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server sent invalid packet."); + } +} + +QByteArray SshIncomingPacket::extractChannelRequestType() const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST); + + try { + quint32 offset = TypeOffset + 1; + SshPacketParser::asUint32(m_data, &offset); + return SshPacketParser::asString(m_data, &offset); + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_REQUEST packet."); + } +} + +void SshIncomingPacket::calculateLength() const +{ + Q_ASSERT(currentDataSize() >= minPacketSize()); + qCDebug(sshLog, "Length field before decryption: %d-%d-%d-%d", m_data.at(0) & 0xff, + m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff); + m_decrypter.decrypt(m_data, 0, cipherBlockSize()); + qCDebug(sshLog, "Length field after decryption: %d-%d-%d-%d", m_data.at(0) & 0xff, m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff); + qCDebug(sshLog, "message type = %d", m_data.at(TypeOffset)); + m_length = SshPacketParser::asUint32(m_data, static_cast(0)); + qCDebug(sshLog, "decrypted length is %u", m_length); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshincomingpacket_p.h b/client/3rd/QtSsh/src/ssh/sshincomingpacket_p.h new file mode 100644 index 00000000..bd7aea4d --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshincomingpacket_p.h @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshpacket_p.h" + +#include "sshcryptofacility_p.h" +#include "sshpacketparser_p.h" + +#include + +namespace QSsh { +namespace Internal { + +class SshKeyExchange; + +struct SshKeyExchangeInit +{ + char cookie[16]; + SshNameList keyAlgorithms; + SshNameList serverHostKeyAlgorithms; + SshNameList encryptionAlgorithmsClientToServer; + SshNameList encryptionAlgorithmsServerToClient; + SshNameList macAlgorithmsClientToServer; + SshNameList macAlgorithmsServerToClient; + SshNameList compressionAlgorithmsClientToServer; + SshNameList compressionAlgorithmsServerToClient; + SshNameList languagesClientToServer; + SshNameList languagesServerToClient; + bool firstKexPacketFollows; +}; + +struct SshKeyExchangeReply +{ + QByteArray k_s; + QList hostKeyParameters; // DSS: p, q, g, y. RSA: e, n. + QByteArray q; // For ECDSA host keys only. + Botan::BigInt f; // For DH only. + QByteArray q_s; // For ECDH only. + QByteArray signatureBlob; +}; + +struct SshDisconnect +{ + quint32 reasonCode; + QString description; + QByteArray language; +}; + +struct SshUserAuthBanner +{ + QString message; + QByteArray language; +}; + +struct SshUserAuthInfoRequestPacket +{ + QString name; + QString instruction; + QByteArray languageTag; + QStringList prompts; + QList echos; +}; + +struct SshDebug +{ + bool display; + QString message; + QByteArray language; +}; + +struct SshUnimplemented +{ + quint32 invalidMsgSeqNr; +}; + +struct SshRequestSuccess +{ + quint32 bindPort; +}; + +struct SshChannelOpen +{ + quint32 remoteChannel; + quint32 remoteWindowSize; + quint32 remoteMaxPacketSize; + QByteArray remoteAddress; + quint32 remotePort; +}; + +struct SshChannelOpenFailure +{ + quint32 localChannel; + quint32 reasonCode; + QString reasonString; + QByteArray language; +}; + +struct SshChannelOpenConfirmation +{ + quint32 localChannel; + quint32 remoteChannel; + quint32 remoteWindowSize; + quint32 remoteMaxPacketSize; +}; + +struct SshChannelWindowAdjust +{ + quint32 localChannel; + quint32 bytesToAdd; +}; + +struct SshChannelData +{ + quint32 localChannel; + QByteArray data; +}; + +struct SshChannelExtendedData +{ + quint32 localChannel; + quint32 type; + QByteArray data; +}; + +struct SshChannelExitStatus +{ + quint32 localChannel; + quint32 exitStatus; +}; + +struct SshChannelExitSignal +{ + quint32 localChannel; + QByteArray signal; + bool coreDumped; + QString error; + QByteArray language; +}; + +class SshIncomingPacket : public AbstractSshPacket +{ +public: + SshIncomingPacket(); + + void consumeData(QByteArray &data); + void recreateKeys(const SshKeyExchange &keyExchange); + void reset(); + + SshKeyExchangeInit extractKeyExchangeInitData() const; + SshKeyExchangeReply extractKeyExchangeReply(const QByteArray &kexAlgo, + const QByteArray &hostKeyAlgo) const; + SshDisconnect extractDisconnect() const; + SshUserAuthBanner extractUserAuthBanner() const; + SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const; + SshDebug extractDebug() const; + SshRequestSuccess extractRequestSuccess() const; + SshUnimplemented extractUnimplemented() const; + + SshChannelOpen extractChannelOpen() const; + SshChannelOpenFailure extractChannelOpenFailure() const; + SshChannelOpenConfirmation extractChannelOpenConfirmation() const; + SshChannelWindowAdjust extractWindowAdjust() const; + SshChannelData extractChannelData() const; + SshChannelExtendedData extractChannelExtendedData() const; + SshChannelExitStatus extractChannelExitStatus() const; + SshChannelExitSignal extractChannelExitSignal() const; + quint32 extractRecipientChannel() const; + QByteArray extractChannelRequestType() const; + + quint32 serverSeqNr() const { return m_serverSeqNr; } + + static const QByteArray ExitStatusType; + static const QByteArray ExitSignalType; + static const QByteArray ForwardedTcpIpType; + +private: + virtual quint32 cipherBlockSize() const; + virtual quint32 macLength() const; + virtual void calculateLength() const; + + void decrypt(); + void moveFirstBytes(QByteArray &target, QByteArray &source, int n); + + quint32 m_serverSeqNr; + SshDecryptionFacility m_decrypter; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshinit.cpp b/client/3rd/QtSsh/src/ssh/sshinit.cpp new file mode 100644 index 00000000..a76724e5 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshinit.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshinit_p.h" + +#include + +#include +#include + +namespace QSsh { +namespace Internal { + +static bool initialized = false; +static QMutex initMutex; + +void initSsh() +{ + QMutexLocker locker(&initMutex); + if (!initialized) { + Botan::LibraryInitializer::initialize("thread_safe=true"); + initialized = true; + } +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshinit_p.h b/client/3rd/QtSsh/src/ssh/sshinit_p.h new file mode 100644 index 00000000..8fb84e27 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshinit_p.h @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +namespace QSsh { +namespace Internal { + +void initSsh(); + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.cpp b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.cpp new file mode 100644 index 00000000..a720e7b3 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshkeycreationdialog.h" +#include "ui_sshkeycreationdialog.h" + +#include "sshkeygenerator.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace QSsh { + +SshKeyCreationDialog::SshKeyCreationDialog(QWidget *parent) + : QDialog(parent), m_keyGenerator(0), m_ui(new Ui::SshKeyCreationDialog) +{ + m_ui->setupUi(this); + // Not using Utils::PathChooser::browseButtonLabel to avoid dependency +#ifdef Q_OS_MAC + m_ui->privateKeyFileButton->setText(tr("Choose...")); +#else + m_ui->privateKeyFileButton->setText(tr("Browse...")); +#endif + const QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QLatin1String("/.ssh/qtc_id"); + setPrivateKeyFile(defaultPath); + + connect(m_ui->rsa, &QRadioButton::toggled, + this, &SshKeyCreationDialog::keyTypeChanged); + connect(m_ui->dsa, &QRadioButton::toggled, + this, &SshKeyCreationDialog::keyTypeChanged); + connect(m_ui->privateKeyFileButton, &QPushButton::clicked, + this, &SshKeyCreationDialog::handleBrowseButtonClicked); + connect(m_ui->generateButton, &QPushButton::clicked, + this, &SshKeyCreationDialog::generateKeys); + keyTypeChanged(); +} + +SshKeyCreationDialog::~SshKeyCreationDialog() +{ + delete m_keyGenerator; + delete m_ui; +} + +void SshKeyCreationDialog::keyTypeChanged() +{ + m_ui->comboBox->clear(); + QStringList keySizes; + if (m_ui->rsa->isChecked()) + keySizes << QLatin1String("1024") << QLatin1String("2048") << QLatin1String("4096"); + else if (m_ui->ecdsa->isChecked()) + keySizes << QLatin1String("256") << QLatin1String("384") << QLatin1String("521"); + else if (m_ui->dsa->isChecked()) + keySizes << QLatin1String("1024"); + m_ui->comboBox->addItems(keySizes); + if (!keySizes.isEmpty()) + m_ui->comboBox->setCurrentIndex(0); + m_ui->comboBox->setEnabled(!keySizes.isEmpty()); +} + +void SshKeyCreationDialog::generateKeys() +{ + if (userForbidsOverwriting()) + return; + + const SshKeyGenerator::KeyType keyType = m_ui->rsa->isChecked() + ? SshKeyGenerator::Rsa : m_ui->dsa->isChecked() + ? SshKeyGenerator::Dsa : SshKeyGenerator::Ecdsa; + + if (!m_keyGenerator) + m_keyGenerator = new SshKeyGenerator; + + QApplication::setOverrideCursor(Qt::BusyCursor); + const bool success = m_keyGenerator->generateKeys(keyType, SshKeyGenerator::Mixed, + m_ui->comboBox->currentText().toUShort()); + QApplication::restoreOverrideCursor(); + + if (success) + saveKeys(); + else + QMessageBox::critical(this, tr("Key Generation Failed"), m_keyGenerator->error()); +} + +void SshKeyCreationDialog::handleBrowseButtonClicked() +{ + const QString filePath = QFileDialog::getSaveFileName(this, tr("Choose Private Key File Name")); + if (!filePath.isEmpty()) + setPrivateKeyFile(filePath); +} + +void SshKeyCreationDialog::setPrivateKeyFile(const QString &filePath) +{ + m_ui->privateKeyFileValueLabel->setText(filePath); + m_ui->generateButton->setEnabled(!privateKeyFilePath().isEmpty()); + m_ui->publicKeyFileLabel->setText(filePath + QLatin1String(".pub")); +} + +void SshKeyCreationDialog::saveKeys() +{ + const QString parentDir = QFileInfo(privateKeyFilePath()).dir().path(); + if (!QDir::root().mkpath(parentDir)) { + QMessageBox::critical(this, tr("Cannot Save Key File"), + tr("Failed to create directory: \"%1\".").arg(parentDir)); + return; + } + + QFile privateKeyFile(privateKeyFilePath()); + if (!privateKeyFile.open(QIODevice::WriteOnly) + || !privateKeyFile.write(m_keyGenerator->privateKey())) { + QMessageBox::critical(this, tr("Cannot Save Private Key File"), + tr("The private key file could not be saved: %1").arg(privateKeyFile.errorString())); + return; + } + QFile::setPermissions(privateKeyFilePath(), QFile::ReadOwner | QFile::WriteOwner); + + QFile publicKeyFile(publicKeyFilePath()); + if (!publicKeyFile.open(QIODevice::WriteOnly) + || !publicKeyFile.write(m_keyGenerator->publicKey())) { + QMessageBox::critical(this, tr("Cannot Save Public Key File"), + tr("The public key file could not be saved: %1").arg(publicKeyFile.errorString())); + return; + } + + accept(); +} + +bool SshKeyCreationDialog::userForbidsOverwriting() +{ + if (!QFileInfo::exists(privateKeyFilePath()) && !QFileInfo::exists(publicKeyFilePath())) + return false; + const QMessageBox::StandardButton reply = QMessageBox::question(this, tr("File Exists"), + tr("There already is a file of that name. Do you want to overwrite it?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + return reply != QMessageBox::Yes; +} + +QString SshKeyCreationDialog::privateKeyFilePath() const +{ + return m_ui->privateKeyFileValueLabel->text(); +} + +QString SshKeyCreationDialog::publicKeyFilePath() const +{ + return m_ui->publicKeyFileLabel->text(); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.h b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.h new file mode 100644 index 00000000..31059c02 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include + +namespace QSsh { +class SshKeyGenerator; + +namespace Ui { class SshKeyCreationDialog; } + +class QSSH_EXPORT SshKeyCreationDialog : public QDialog +{ + Q_OBJECT +public: + SshKeyCreationDialog(QWidget *parent = 0); + ~SshKeyCreationDialog(); + + QString privateKeyFilePath() const; + QString publicKeyFilePath() const; + +private: + void keyTypeChanged(); + void generateKeys(); + void handleBrowseButtonClicked(); + void setPrivateKeyFile(const QString &filePath); + void saveKeys(); + bool userForbidsOverwriting(); + +private: + SshKeyGenerator *m_keyGenerator; + Ui::SshKeyCreationDialog *m_ui; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.ui b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.ui new file mode 100644 index 00000000..eb3347e8 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeycreationdialog.ui @@ -0,0 +1,264 @@ + + + QSsh::SshKeyCreationDialog + + + true + + + + 0 + 0 + 380 + 231 + + + + + 0 + 0 + + + + SSH Key Configuration + + + + + + Options + + + + + + Key algorithm: + + + + + + + + + + 0 + 0 + + + + &RSA + + + true + + + + + + + + 0 + 0 + + + + &DSA + + + + + + + ECDSA + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + Key &size: + + + comboBox + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Private key file: + + + + + + + + + + + + + + + + Browse... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Public key file: + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 6 + + + + + + 0 + 0 + + + + &Generate And Save Key Pair + + + + + + + + 0 + 0 + + + + &Cancel + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + + + closeButton + clicked() + QSsh::SshKeyCreationDialog + close() + + + 195 + 184 + + + 381 + 107 + + + + + diff --git a/client/3rd/QtSsh/src/ssh/sshkeyexchange.cpp b/client/3rd/QtSsh/src/ssh/sshkeyexchange.cpp new file mode 100644 index 00000000..cdcb4555 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeyexchange.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshkeyexchange_p.h" + +#include "ssh_global.h" +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" + +#include + +#include + +using namespace Botan; + +namespace QSsh { +namespace Internal { + +namespace { + + // For debugging + void printNameList(const char *listName, const SshNameList &list) + { + qCDebug(sshLog, "%s:", listName); + foreach (const QByteArray &name, list.names) + qCDebug(sshLog, "%s", name.constData()); + } + + void printData(const char *name, const QByteArray &data) + { + qCDebug(sshLog, "The client thinks the %s has length %d and is: %s", name, data.count(), + data.toHex().constData()); + } + +} // anonymous namespace + +SshKeyExchange::SshKeyExchange(const SshConnectionParameters &connParams, + SshSendFacility &sendFacility) + : m_connParams(connParams), m_sendFacility(sendFacility) +{ +} + +SshKeyExchange::~SshKeyExchange() {} + +void SshKeyExchange::sendKexInitPacket(const QByteArray &serverId) +{ + m_serverId = serverId; + m_clientKexInitPayload = m_sendFacility.sendKeyExchangeInitPacket(); +} + +bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit) +{ + qCDebug(sshLog, "server requests key exchange"); + serverKexInit.printRawBytes(); + SshKeyExchangeInit kexInitParams + = serverKexInit.extractKeyExchangeInitData(); + + printNameList("Key Algorithms", kexInitParams.keyAlgorithms); + printNameList("Server Host Key Algorithms", kexInitParams.serverHostKeyAlgorithms); + printNameList("Encryption algorithms client to server", kexInitParams.encryptionAlgorithmsClientToServer); + printNameList("Encryption algorithms server to client", kexInitParams.encryptionAlgorithmsServerToClient); + printNameList("MAC algorithms client to server", kexInitParams.macAlgorithmsClientToServer); + printNameList("MAC algorithms server to client", kexInitParams.macAlgorithmsServerToClient); + printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer); + printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer); + printNameList("Languages client to server", kexInitParams.languagesClientToServer); + printNameList("Languages server to client", kexInitParams.languagesServerToClient); + qCDebug(sshLog, "First packet follows: %d", kexInitParams.firstKexPacketFollows); + + m_kexAlgoName = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods, + kexInitParams.keyAlgorithms.names); + m_serverHostKeyAlgo = SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms, + kexInitParams.serverHostKeyAlgorithms.names); + determineHashingAlgorithm(kexInitParams, true); + determineHashingAlgorithm(kexInitParams, false); + + m_encryptionAlgo + = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, + kexInitParams.encryptionAlgorithmsClientToServer.names); + m_decryptionAlgo + = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, + kexInitParams.encryptionAlgorithmsServerToClient.names); + SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, + kexInitParams.compressionAlgorithmsClientToServer.names); + SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, + kexInitParams.compressionAlgorithmsServerToClient.names); + + AutoSeeded_RNG rng; + if (m_kexAlgoName.startsWith(SshCapabilities::EcdhKexNamePrefix)) { + m_ecdhKey.reset(new ECDH_PrivateKey(rng, EC_Group(botanKeyExchangeAlgoName(m_kexAlgoName)))); + m_sendFacility.sendKeyEcdhInitPacket(convertByteArray(m_ecdhKey->public_value())); + } else { + m_dhKey.reset(new DH_PrivateKey(rng, DL_Group(botanKeyExchangeAlgoName(m_kexAlgoName)))); + m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y()); + } + + m_serverKexInitPayload = serverKexInit.payLoad(); + return kexInitParams.firstKexPacketFollows; +} + +void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply, + const QByteArray &clientId) +{ + + const SshKeyExchangeReply &reply + = dhReply.extractKeyExchangeReply(m_kexAlgoName, m_serverHostKeyAlgo); + if (m_dhKey && (reply.f <= 0 || reply.f >= m_dhKey->group_p())) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Server sent invalid f."); + } + + QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId); + concatenatedData += AbstractSshPacket::encodeString(m_serverId); + concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload); + concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload); + concatenatedData += reply.k_s; + + printData("Client Id", AbstractSshPacket::encodeString(clientId)); + printData("Server Id", AbstractSshPacket::encodeString(m_serverId)); + printData("Client Payload", AbstractSshPacket::encodeString(m_clientKexInitPayload)); + printData("Server payload", AbstractSshPacket::encodeString(m_serverKexInitPayload)); + printData("K_S", reply.k_s); + + SecureVector encodedK; + if (m_dhKey) { + concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y()); + concatenatedData += AbstractSshPacket::encodeMpInt(reply.f); + DH_KA_Operation dhOp(*m_dhKey); + SecureVector encodedF = BigInt::encode(reply.f); + encodedK = dhOp.agree(encodedF, encodedF.size()); + printData("y", AbstractSshPacket::encodeMpInt(m_dhKey->get_y())); + printData("f", AbstractSshPacket::encodeMpInt(reply.f)); + m_dhKey.reset(nullptr); + } else { + Q_ASSERT(m_ecdhKey); + concatenatedData // Q_C. + += AbstractSshPacket::encodeString(convertByteArray(m_ecdhKey->public_value())); + concatenatedData += AbstractSshPacket::encodeString(reply.q_s); + ECDH_KA_Operation ecdhOp(*m_ecdhKey); + encodedK = ecdhOp.agree(convertByteArray(reply.q_s), reply.q_s.count()); + m_ecdhKey.reset(nullptr); + } + + const BigInt k = BigInt::decode(encodedK); + m_k = AbstractSshPacket::encodeMpInt(k); // Roundtrip, as Botan encodes BigInts somewhat differently. + printData("K", m_k); + concatenatedData += m_k; + printData("Concatenated data", concatenatedData); + + m_hash.reset(get_hash(botanHMacAlgoName(hashAlgoForKexAlgo()))); + const SecureVector &hashResult = m_hash->process(convertByteArray(concatenatedData), + concatenatedData.size()); + m_h = convertByteArray(hashResult); + printData("H", m_h); + + QScopedPointer sigKey; + if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) { + const DL_Group group(reply.hostKeyParameters.at(0), reply.hostKeyParameters.at(1), + reply.hostKeyParameters.at(2)); + DSA_PublicKey * const dsaKey + = new DSA_PublicKey(group, reply.hostKeyParameters.at(3)); + sigKey.reset(dsaKey); + } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { + RSA_PublicKey * const rsaKey + = new RSA_PublicKey(reply.hostKeyParameters.at(1), reply.hostKeyParameters.at(0)); + sigKey.reset(rsaKey); + } else { + QSSH_ASSERT_AND_RETURN(m_serverHostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix)); + const EC_Group domain(SshCapabilities::oid(m_serverHostKeyAlgo)); + const PointGFp point = OS2ECP(convertByteArray(reply.q), reply.q.count(), + domain.get_curve()); + ECDSA_PublicKey * const ecdsaKey = new ECDSA_PublicKey(domain, point); + sigKey.reset(ecdsaKey); + } + + const byte * const botanH = convertByteArray(m_h); + const Botan::byte * const botanSig = convertByteArray(reply.signatureBlob); + PK_Verifier verifier(*sigKey, botanEmsaAlgoName(m_serverHostKeyAlgo)); + if (!verifier.verify_message(botanH, m_h.size(), botanSig, reply.signatureBlob.size())) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Invalid signature in key exchange reply packet."); + } + + checkHostKey(reply.k_s); + + m_sendFacility.sendNewKeysPacket(); +} + +QByteArray SshKeyExchange::hashAlgoForKexAlgo() const +{ + if (m_kexAlgoName == SshCapabilities::EcdhNistp256) + return SshCapabilities::HMacSha256; + if (m_kexAlgoName == SshCapabilities::EcdhNistp384) + return SshCapabilities::HMacSha384; + if (m_kexAlgoName == SshCapabilities::EcdhNistp521) + return SshCapabilities::HMacSha512; + return SshCapabilities::HMacSha1; +} + +void SshKeyExchange::determineHashingAlgorithm(const SshKeyExchangeInit &kexInit, + bool serverToClient) +{ + QByteArray * const algo = serverToClient ? &m_s2cHMacAlgo : &m_c2sHMacAlgo; + const QList &serverCapabilities = serverToClient + ? kexInit.macAlgorithmsServerToClient.names + : kexInit.macAlgorithmsClientToServer.names; + *algo = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, serverCapabilities); +} + +void SshKeyExchange::checkHostKey(const QByteArray &hostKey) +{ + if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingNone) { + if (m_connParams.hostKeyDatabase) + m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host, hostKey); + return; + } + + if (!m_connParams.hostKeyDatabase) { + throw SshClientException(SshInternalError, + SSH_TR("Host key database must exist " + "if host key checking is enabled.")); + } + + switch (m_connParams.hostKeyDatabase->matchHostKey(m_connParams.host, hostKey)) { + case SshHostKeyDatabase::KeyLookupMatch: + return; // Nothing to do. + case SshHostKeyDatabase::KeyLookupMismatch: + if (m_connParams.hostKeyCheckingMode != SshHostKeyCheckingAllowMismatch) + throwHostKeyException(); + break; + case SshHostKeyDatabase::KeyLookupNoMatch: + if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingStrict) + throwHostKeyException(); + break; + } + m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host, hostKey); +} + +void SshKeyExchange::throwHostKeyException() +{ + throw SshServerException(SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Host key changed", + SSH_TR("Host key of machine \"%1\" has changed.") + .arg(m_connParams.host)); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeyexchange_p.h b/client/3rd/QtSsh/src/ssh/sshkeyexchange_p.h new file mode 100644 index 00000000..b56597b6 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeyexchange_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshconnection.h" + +#include +#include + +namespace Botan { +class DH_PrivateKey; +class ECDH_PrivateKey; +class HashFunction; +} + +namespace QSsh { +namespace Internal { + +struct SshKeyExchangeInit; +class SshSendFacility; +class SshIncomingPacket; + +class SshKeyExchange +{ +public: + SshKeyExchange(const SshConnectionParameters &connParams, SshSendFacility &sendFacility); + ~SshKeyExchange(); + + void sendKexInitPacket(const QByteArray &serverId); + + // Returns true <=> the server sends a guessed package. + bool sendDhInitPacket(const SshIncomingPacket &serverKexInit); + + void sendNewKeysPacket(const SshIncomingPacket &dhReply, + const QByteArray &clientId); + + QByteArray k() const { return m_k; } + QByteArray h() const { return m_h; } + Botan::HashFunction *hash() const { return m_hash.data(); } + QByteArray encryptionAlgo() const { return m_encryptionAlgo; } + QByteArray decryptionAlgo() const { return m_decryptionAlgo; } + QByteArray hMacAlgoClientToServer() const { return m_c2sHMacAlgo; } + QByteArray hMacAlgoServerToClient() const { return m_s2cHMacAlgo; } + +private: + QByteArray hashAlgoForKexAlgo() const; + void determineHashingAlgorithm(const SshKeyExchangeInit &kexInit, bool serverToClient); + void checkHostKey(const QByteArray &hostKey); + Q_NORETURN void throwHostKeyException(); + + QByteArray m_serverId; + QByteArray m_clientKexInitPayload; + QByteArray m_serverKexInitPayload; + QScopedPointer m_dhKey; + QScopedPointer m_ecdhKey; + QByteArray m_kexAlgoName; + QByteArray m_k; + QByteArray m_h; + QByteArray m_serverHostKeyAlgo; + QByteArray m_encryptionAlgo; + QByteArray m_decryptionAlgo; + QByteArray m_c2sHMacAlgo; + QByteArray m_s2cHMacAlgo; + QScopedPointer m_hash; + const SshConnectionParameters m_connParams; + SshSendFacility &m_sendFacility; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeygenerator.cpp b/client/3rd/QtSsh/src/ssh/sshkeygenerator.cpp new file mode 100644 index 00000000..eb85c1aa --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeygenerator.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshkeygenerator.h" + +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "ssh_global.h" +#include "sshinit_p.h" +#include "sshpacket_p.h" + +#include + +#include +#include + +#include + +namespace QSsh { + +using namespace Botan; +using namespace Internal; + +SshKeyGenerator::SshKeyGenerator() : m_type(Rsa) +{ + initSsh(); +} + +bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int keySize, + EncryptionMode encryptionMode) +{ + m_type = type; + m_encryptionMode = encryptionMode; + + try { + AutoSeeded_RNG rng; + KeyPtr key; + switch (m_type) { + case Rsa: + key = KeyPtr(new RSA_PrivateKey(rng, keySize)); + break; + case Dsa: + key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize))); + break; + case Ecdsa: { + const QByteArray algo = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(keySize / 8); + key = KeyPtr(new ECDSA_PrivateKey(rng, EC_Group(SshCapabilities::oid(algo)))); + break; + } + } + switch (format) { + case Pkcs8: + generatePkcs8KeyStrings(key, rng); + break; + case OpenSsl: + generateOpenSslKeyStrings(key); + break; + case Mixed: + default: + generatePkcs8KeyString(key, true, rng); + generateOpenSslPublicKeyString(key); + } + return true; + } catch (const std::exception &e) { + m_error = tr("Error generating key: %1").arg(QString::fromLatin1(e.what())); + return false; + } +} + +void SshKeyGenerator::generatePkcs8KeyStrings(const KeyPtr &key, RandomNumberGenerator &rng) +{ + generatePkcs8KeyString(key, false, rng); + generatePkcs8KeyString(key, true, rng); +} + +void SshKeyGenerator::generatePkcs8KeyString(const KeyPtr &key, bool privateKey, + RandomNumberGenerator &rng) +{ + Pipe pipe; + pipe.start_msg(); + QByteArray *keyData; + if (privateKey) { + QString password; + if (m_encryptionMode == DoOfferEncryption) + password = getPassword(); + if (!password.isEmpty()) + pipe.write(PKCS8::PEM_encode(*key, rng, password.toLocal8Bit().data())); + else + pipe.write(PKCS8::PEM_encode(*key)); + keyData = &m_privateKey; + } else { + pipe.write(X509::PEM_encode(*key)); + keyData = &m_publicKey; + } + pipe.end_msg(); + keyData->resize(static_cast(pipe.remaining(pipe.message_count() - 1))); + pipe.read(convertByteArray(*keyData), keyData->size(), + pipe.message_count() - 1); +} + +void SshKeyGenerator::generateOpenSslKeyStrings(const KeyPtr &key) +{ + generateOpenSslPublicKeyString(key); + generateOpenSslPrivateKeyString(key); +} + +void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key) +{ + QList params; + QByteArray keyId; + QByteArray q; + switch (m_type) { + case Rsa: { + const QSharedPointer rsaKey = key.dynamicCast(); + params << rsaKey->get_e() << rsaKey->get_n(); + keyId = SshCapabilities::PubKeyRsa; + break; + } + case Dsa: { + const QSharedPointer dsaKey = key.dynamicCast(); + params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y(); + keyId = SshCapabilities::PubKeyDss; + break; + } + case Ecdsa: { + const auto ecdsaKey = key.dynamicCast(); + q = convertByteArray(EC2OSP(ecdsaKey->public_point(), PointGFp::UNCOMPRESSED)); + keyId = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( + static_cast(ecdsaKey->private_value().bytes())); + break; + } + } + + QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId); + foreach (const BigInt &b, params) + publicKeyBlob += AbstractSshPacket::encodeMpInt(b); + if (!q.isEmpty()) { + publicKeyBlob += AbstractSshPacket::encodeString(keyId.mid(11)); // Without "ecdsa-sha2-" prefix. + publicKeyBlob += AbstractSshPacket::encodeString(q); + } + publicKeyBlob = publicKeyBlob.toBase64(); + const QByteArray id = "QtCreator/" + + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8(); + m_publicKey = keyId + ' ' + publicKeyBlob + ' ' + id; +} + +void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key) +{ + QList params; + const char *label = ""; + switch (m_type) { + case Rsa: { + const QSharedPointer rsaKey + = key.dynamicCast(); + params << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() << rsaKey->get_p() + << rsaKey->get_q(); + const BigInt dmp1 = rsaKey->get_d() % (rsaKey->get_p() - 1); + const BigInt dmq1 = rsaKey->get_d() % (rsaKey->get_q() - 1); + const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p()); + params << dmp1 << dmq1 << iqmp; + label = "RSA PRIVATE KEY"; + break; + } + case Dsa: { + const QSharedPointer dsaKey = key.dynamicCast(); + params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y() + << dsaKey->get_x(); + label = "DSA PRIVATE KEY"; + break; + } + case Ecdsa: + params << key.dynamicCast()->private_value(); + label = "EC PRIVATE KEY"; + break; + } + + DER_Encoder encoder; + encoder.start_cons(SEQUENCE).encode(size_t(0)); + foreach (const BigInt &b, params) + encoder.encode(b); + encoder.end_cons(); + m_privateKey = QByteArray(PEM_Code::encode (encoder.get_contents(), label).c_str()); +} + +QString SshKeyGenerator::getPassword() const +{ + QInputDialog d; + d.setInputMode(QInputDialog::TextInput); + d.setTextEchoMode(QLineEdit::Password); + d.setWindowTitle(tr("Password for Private Key")); + d.setLabelText(tr("It is recommended that you secure your private key\n" + "with a password, which you can enter below.")); + d.setOkButtonText(tr("Encrypt Key File")); + d.setCancelButtonText(tr("Do Not Encrypt Key File")); + int result = QDialog::Accepted; + QString password; + while (result == QDialog::Accepted && password.isEmpty()) { + result = d.exec(); + password = d.textValue(); + } + return result == QDialog::Accepted ? password : QString(); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeygenerator.h b/client/3rd/QtSsh/src/ssh/sshkeygenerator.h new file mode 100644 index 00000000..48361442 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeygenerator.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include +#include + +namespace Botan { + class Private_Key; + class RandomNumberGenerator; +} + +namespace QSsh { + +class QSSH_EXPORT SshKeyGenerator +{ + Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator) +public: + enum KeyType { Rsa, Dsa, Ecdsa }; + enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed }; + enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format. + + SshKeyGenerator(); + bool generateKeys(KeyType type, PrivateKeyFormat format, int keySize, + EncryptionMode encryptionMode = DoOfferEncryption); + + QString error() const { return m_error; } + QByteArray privateKey() const { return m_privateKey; } + QByteArray publicKey() const { return m_publicKey; } + KeyType type() const { return m_type; } + +private: + typedef QSharedPointer KeyPtr; + + void generatePkcs8KeyStrings(const KeyPtr &key, Botan::RandomNumberGenerator &rng); + void generatePkcs8KeyString(const KeyPtr &key, bool privateKey, + Botan::RandomNumberGenerator &rng); + void generateOpenSslKeyStrings(const KeyPtr &key); + void generateOpenSslPrivateKeyString(const KeyPtr &key); + void generateOpenSslPublicKeyString(const KeyPtr &key); + QString getPassword() const; + + QString m_error; + QByteArray m_publicKey; + QByteArray m_privateKey; + KeyType m_type; + EncryptionMode m_encryptionMode; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever.cpp b/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever.cpp new file mode 100644 index 00000000..8f133623 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshkeypasswordretriever_p.h" + +#include +#include +#include + +#include + +namespace QSsh { +namespace Internal { + +std::string SshKeyPasswordRetriever::get_passphrase(const std::string &, const std::string &, + UI_Result &result) const +{ + const bool hasGui = dynamic_cast(QApplication::instance()); + if (hasGui) { + bool ok; + const QString &password = QInputDialog::getText(0, + QCoreApplication::translate("QSsh::Ssh", "Password Required"), + QCoreApplication::translate("QSsh::Ssh", "Please enter the password for your private key."), + QLineEdit::Password, QString(), &ok); + result = ok ? OK : CANCEL_ACTION; + return std::string(password.toLocal8Bit().data()); + } else { + result = OK; + std::string password; + std::cout << "Please enter the password for your private key (set echo off beforehand!): " << std::flush; + std::cin >> password; + return password; + } +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever_p.h b/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever_p.h new file mode 100644 index 00000000..15301feb --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshkeypasswordretriever_p.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace QSsh { +namespace Internal { + +class SshKeyPasswordRetriever : public Botan::User_Interface +{ +public: + std::string get_passphrase(const std::string &what, const std::string &source, + UI_Result &result) const; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshlogging.cpp b/client/3rd/QtSsh/src/ssh/sshlogging.cpp new file mode 100644 index 00000000..9a72ff92 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshlogging.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshlogging_p.h" + +namespace QSsh { +namespace Internal { +Q_LOGGING_CATEGORY(sshLog, "qtc.ssh") +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshlogging_p.h b/client/3rd/QtSsh/src/ssh/sshlogging_p.h new file mode 100644 index 00000000..07815313 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshlogging_p.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace QSsh { +namespace Internal { +Q_DECLARE_LOGGING_CATEGORY(sshLog) +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshoutgoingpacket.cpp b/client/3rd/QtSsh/src/ssh/sshoutgoingpacket.cpp new file mode 100644 index 00000000..c74a8950 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshoutgoingpacket.cpp @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshoutgoingpacket_p.h" + +#include "sshcapabilities_p.h" +#include "sshcryptofacility_p.h" +#include "sshlogging_p.h" + +#include + +namespace QSsh { +namespace Internal { + +SshOutgoingPacket::SshOutgoingPacket(const SshEncryptionFacility &encrypter, + const quint32 &seqNr) : m_encrypter(encrypter), m_seqNr(seqNr) +{ +} + +quint32 SshOutgoingPacket::cipherBlockSize() const +{ + return qMax(m_encrypter.cipherBlockSize(), 4U); +} + +quint32 SshOutgoingPacket::macLength() const +{ + return m_encrypter.macLength(); +} + +QByteArray SshOutgoingPacket::generateKeyExchangeInitPacket() +{ + const QByteArray &supportedkeyExchangeMethods + = encodeNameList(SshCapabilities::KeyExchangeMethods); + const QByteArray &supportedPublicKeyAlgorithms + = encodeNameList(SshCapabilities::PublicKeyAlgorithms); + const QByteArray &supportedEncryptionAlgorithms + = encodeNameList(SshCapabilities::EncryptionAlgorithms); + const QByteArray &supportedMacAlgorithms + = encodeNameList(SshCapabilities::MacAlgorithms); + const QByteArray &supportedCompressionAlgorithms + = encodeNameList(SshCapabilities::CompressionAlgorithms); + const QByteArray &supportedLanguages = encodeNameList(QList()); + + init(SSH_MSG_KEXINIT); + m_data += m_encrypter.getRandomNumbers(16); + m_data.append(supportedkeyExchangeMethods); + m_data.append(supportedPublicKeyAlgorithms); + m_data.append(supportedEncryptionAlgorithms) + .append(supportedEncryptionAlgorithms); + m_data.append(supportedMacAlgorithms).append(supportedMacAlgorithms); + m_data.append(supportedCompressionAlgorithms) + .append(supportedCompressionAlgorithms); + m_data.append(supportedLanguages).append(supportedLanguages); + appendBool(false); // No guessed packet. + m_data.append(QByteArray(4, 0)); // Reserved. + QByteArray payload = m_data.mid(PayloadOffset); + finalize(); + return payload; +} + +void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e) +{ + init(SSH_MSG_KEXDH_INIT).appendMpInt(e).finalize(); +} + +void SshOutgoingPacket::generateKeyEcdhInitPacket(const QByteArray &clientQ) +{ + init(SSH_MSG_KEX_ECDH_INIT).appendString(clientQ).finalize(); +} + +void SshOutgoingPacket::generateNewKeysPacket() +{ + init(SSH_MSG_NEWKEYS).finalize(); +} + +void SshOutgoingPacket::generateUserAuthServiceRequestPacket() +{ + generateServiceRequest("ssh-userauth"); +} + +void SshOutgoingPacket::generateServiceRequest(const QByteArray &service) +{ + init(SSH_MSG_SERVICE_REQUEST).appendString(service).finalize(); +} + +void SshOutgoingPacket::generateUserAuthByPasswordRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd) +{ + init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service); + if (pwd.isEmpty()) + appendString("none"); // RFC 4252, 5.2 + else + appendString("password").appendBool(false).appendString(pwd); + finalize(); +} + +void SshOutgoingPacket::generateUserAuthByPublicKeyRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) + .appendString("publickey").appendBool(true) + .appendString(m_encrypter.authenticationAlgorithmName()) + .appendString(m_encrypter.authenticationPublicKey()); + const QByteArray &dataToSign = m_data.mid(PayloadOffset); + appendString(m_encrypter.authenticationKeySignature(dataToSign)); + finalize(); +} + +void SshOutgoingPacket::generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + // RFC 4256, 3.1 + init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) + .appendString("keyboard-interactive") + .appendString(QByteArray()) // Language tag. Deprecated and should be empty + .appendString(QByteArray()) // Submethods. + .finalize(); +} + +void SshOutgoingPacket::generateUserAuthInfoResponsePacket(const QStringList &responses) +{ + // RFC 4256, 3.4 + init(SSH_MSG_USERAUTH_INFO_RESPONSE).appendInt(responses.count()); + foreach (const QString &response, responses) + appendString(response.toUtf8()); + finalize(); +} + +void SshOutgoingPacket::generateRequestFailurePacket() +{ + init(SSH_MSG_REQUEST_FAILURE).finalize(); +} + +void SshOutgoingPacket::generateIgnorePacket() +{ + init(SSH_MSG_IGNORE).finalize(); +} + +void SshOutgoingPacket::generateInvalidMessagePacket() +{ + init(SSH_MSG_INVALID).finalize(); +} + +void SshOutgoingPacket::generateSessionPacket(quint32 channelId, + quint32 windowSize, quint32 maxPacketSize) +{ + init(SSH_MSG_CHANNEL_OPEN).appendString("session").appendInt(channelId) + .appendInt(windowSize).appendInt(maxPacketSize).finalize(); +} + +void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort, + const QByteArray &localIpAddress, quint32 localPort) +{ + init(SSH_MSG_CHANNEL_OPEN).appendString("direct-tcpip").appendInt(channelId) + .appendInt(windowSize).appendInt(maxPacketSize).appendString(remoteHost) + .appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize(); +} + +void SshOutgoingPacket::generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort) +{ + init(SSH_MSG_GLOBAL_REQUEST).appendString("tcpip-forward").appendBool(true) + .appendString(bindAddress).appendInt(bindPort).finalize(); +} + +void SshOutgoingPacket::generateCancelTcpIpForwardPacket(const QByteArray &bindAddress, + quint32 bindPort) +{ + init(SSH_MSG_GLOBAL_REQUEST).appendString("cancel-tcpip-forward").appendBool(true) + .appendString(bindAddress).appendInt(bindPort).finalize(); +} + +void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel, + const QByteArray &var, const QByteArray &value) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("env") + .appendBool(false).appendString(var).appendString(value).finalize(); +} + +void SshOutgoingPacket::generatePtyRequestPacket(quint32 remoteChannel, + const SshPseudoTerminal &terminal) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel) + .appendString("pty-req").appendBool(false) + .appendString(terminal.termType).appendInt(terminal.columnCount) + .appendInt(terminal.rowCount).appendInt(0).appendInt(0); + QByteArray modeString; + for (SshPseudoTerminal::ModeMap::ConstIterator it = terminal.modes.constBegin(); + it != terminal.modes.constEnd(); ++it) { + modeString += char(it.key()); + modeString += encodeInt(it.value()); + } + modeString += char(0); // TTY_OP_END + appendString(modeString).finalize(); +} + +void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel, + const QByteArray &command) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("exec") + .appendBool(true).appendString(command).finalize(); +} + +void SshOutgoingPacket::generateShellPacket(quint32 remoteChannel) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("shell") + .appendBool(true).finalize(); +} + +void SshOutgoingPacket::generateSftpPacket(quint32 remoteChannel) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel) + .appendString("subsystem").appendBool(true).appendString("sftp") + .finalize(); +} + +void SshOutgoingPacket::generateWindowAdjustPacket(quint32 remoteChannel, + quint32 bytesToAdd) +{ + init(SSH_MSG_CHANNEL_WINDOW_ADJUST).appendInt(remoteChannel) + .appendInt(bytesToAdd).finalize(); +} + +void SshOutgoingPacket::generateChannelDataPacket(quint32 remoteChannel, + const QByteArray &data) +{ + init(SSH_MSG_CHANNEL_DATA).appendInt(remoteChannel).appendString(data) + .finalize(); +} + +void SshOutgoingPacket::generateChannelSignalPacket(quint32 remoteChannel, + const QByteArray &signalName) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel) + .appendString("signal").appendBool(false).appendString(signalName) + .finalize(); +} + +void SshOutgoingPacket::generateChannelEofPacket(quint32 remoteChannel) +{ + init(SSH_MSG_CHANNEL_EOF).appendInt(remoteChannel).finalize(); +} + +void SshOutgoingPacket::generateChannelClosePacket(quint32 remoteChannel) +{ + init(SSH_MSG_CHANNEL_CLOSE).appendInt(remoteChannel).finalize(); +} + +void SshOutgoingPacket::generateChannelOpenConfirmationPacket(quint32 remoteChannel, + quint32 localChannel, + quint32 localWindowSize, + quint32 maxPacketSize) +{ + init(SSH_MSG_CHANNEL_OPEN_CONFIRMATION).appendInt(remoteChannel).appendInt(localChannel) + .appendInt(localWindowSize).appendInt(maxPacketSize).finalize(); +} + +void SshOutgoingPacket::generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason, + const QByteArray &reasonString) +{ + init(SSH_MSG_CHANNEL_OPEN_FAILURE).appendInt(remoteChannel).appendInt(reason) + .appendString(reasonString).appendString(QByteArray()).finalize(); +} + +void SshOutgoingPacket::generateDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString) +{ + init(SSH_MSG_DISCONNECT).appendInt(reason).appendString(reasonString) + .appendString(QByteArray()).finalize(); +} + +void SshOutgoingPacket::generateMsgUnimplementedPacket(quint32 serverSeqNr) +{ + init(SSH_MSG_UNIMPLEMENTED).appendInt(serverSeqNr).finalize(); +} + +SshOutgoingPacket &SshOutgoingPacket::appendInt(quint32 val) +{ + m_data.append(encodeInt(val)); + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::appendMpInt(const Botan::BigInt &number) +{ + m_data.append(encodeMpInt(number)); + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::appendBool(bool b) +{ + m_data += static_cast(b); + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::appendString(const QByteArray &string) +{ + m_data.append(encodeString(string)); + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::init(SshPacketType type) +{ + m_data.resize(TypeOffset + 1); + m_data[TypeOffset] = type; + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::setPadding() +{ + m_data += m_encrypter.getRandomNumbers(MinPaddingLength); + int padLength = MinPaddingLength; + const int divisor = sizeDivisor(); + const int mod = m_data.size() % divisor; + padLength += divisor - mod; + m_data += m_encrypter.getRandomNumbers(padLength - MinPaddingLength); + m_data[PaddingLengthOffset] = padLength; + return *this; +} + +SshOutgoingPacket &SshOutgoingPacket::encrypt() +{ + const QByteArray &mac + = generateMac(m_encrypter, m_seqNr); + m_encrypter.encrypt(m_data); + m_data += mac; + return *this; +} + +void SshOutgoingPacket::finalize() +{ + setPadding(); + setLengthField(m_data); + m_length = m_data.size() - 4; + qCDebug(sshLog, "Encrypting packet of type %u", m_data.at(TypeOffset)); + encrypt(); + qCDebug(sshLog, "Sending packet of size %d", rawData().count()); + Q_ASSERT(isComplete()); +} + +int SshOutgoingPacket::sizeDivisor() const +{ + return qMax(cipherBlockSize(), 8U); +} + +QByteArray SshOutgoingPacket::encodeNameList(const QList &list) +{ + QByteArray data; + data.resize(4); + for (int i = 0; i < list.count(); ++i) { + if (i > 0) + data.append(','); + data.append(list.at(i)); + } + AbstractSshPacket::setLengthField(data); + return data; +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshoutgoingpacket_p.h b/client/3rd/QtSsh/src/ssh/sshoutgoingpacket_p.h new file mode 100644 index 00000000..d2d4f63f --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshoutgoingpacket_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshpacket_p.h" + +#include "sshpseudoterminal.h" + +#include + +namespace QSsh { +namespace Internal { + +class SshEncryptionFacility; + +class SshOutgoingPacket : public AbstractSshPacket +{ +public: + SshOutgoingPacket(const SshEncryptionFacility &encrypter, + const quint32 &seqNr); + + QByteArray generateKeyExchangeInitPacket(); // Returns payload. + void generateKeyDhInitPacket(const Botan::BigInt &e); + void generateKeyEcdhInitPacket(const QByteArray &clientQ); + void generateNewKeysPacket(); + void generateDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString); + void generateMsgUnimplementedPacket(quint32 serverSeqNr); + void generateUserAuthServiceRequestPacket(); + void generateUserAuthByPasswordRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd); + void generateUserAuthByPublicKeyRequestPacket(const QByteArray &user, + const QByteArray &service); + void generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user, + const QByteArray &service); + void generateUserAuthInfoResponsePacket(const QStringList &responses); + void generateRequestFailurePacket(); + void generateIgnorePacket(); + void generateInvalidMessagePacket(); + void generateSessionPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize); + void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort, + const QByteArray &localIpAddress, quint32 localPort); + void generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort); + void generateCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort); + void generateEnvPacket(quint32 remoteChannel, const QByteArray &var, + const QByteArray &value); + void generatePtyRequestPacket(quint32 remoteChannel, + const SshPseudoTerminal &terminal); + void generateExecPacket(quint32 remoteChannel, const QByteArray &command); + void generateShellPacket(quint32 remoteChannel); + void generateSftpPacket(quint32 remoteChannel); + void generateWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd); + void generateChannelDataPacket(quint32 remoteChannel, + const QByteArray &data); + void generateChannelSignalPacket(quint32 remoteChannel, + const QByteArray &signalName); + void generateChannelEofPacket(quint32 remoteChannel); + void generateChannelClosePacket(quint32 remoteChannel); + void generateChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel, + quint32 localWindowSize, quint32 maxPackeSize); + void generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason, + const QByteArray &reasonString); + +private: + virtual quint32 cipherBlockSize() const; + virtual quint32 macLength() const; + + static QByteArray encodeNameList(const QList &list); + + void generateServiceRequest(const QByteArray &service); + + SshOutgoingPacket &init(SshPacketType type); + SshOutgoingPacket &setPadding(); + SshOutgoingPacket &encrypt(); + void finalize(); + + SshOutgoingPacket &appendInt(quint32 val); + SshOutgoingPacket &appendString(const QByteArray &string); + SshOutgoingPacket &appendMpInt(const Botan::BigInt &number); + SshOutgoingPacket &appendBool(bool b); + int sizeDivisor() const; + + const SshEncryptionFacility &m_encrypter; + const quint32 &m_seqNr; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshpacket.cpp b/client/3rd/QtSsh/src/ssh/sshpacket.cpp new file mode 100644 index 00000000..1b35037f --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshpacket.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshpacket_p.h" + +#include "sshcapabilities_p.h" +#include "sshcryptofacility_p.h" +#include "sshexception_p.h" +#include "sshlogging_p.h" +#include "sshpacketparser_p.h" + +#include + +#include + +namespace QSsh { +namespace Internal { + +const quint32 AbstractSshPacket::PaddingLengthOffset = 4; +const quint32 AbstractSshPacket::PayloadOffset = PaddingLengthOffset + 1; +const quint32 AbstractSshPacket::TypeOffset = PayloadOffset; +const quint32 AbstractSshPacket::MinPaddingLength = 4; + +static void printByteArray(const QByteArray &data) +{ + qCDebug(sshLog, "%s", data.toHex().constData()); +} + + +AbstractSshPacket::AbstractSshPacket() : m_length(0) { } +AbstractSshPacket::~AbstractSshPacket() {} + +bool AbstractSshPacket::isComplete() const +{ + if (currentDataSize() < minPacketSize()) + return false; + return 4 + length() + macLength() == currentDataSize(); +} + +void AbstractSshPacket::clear() +{ + m_data.clear(); + m_length = 0; +} + +SshPacketType AbstractSshPacket::type() const +{ + Q_ASSERT(isComplete()); + return static_cast(m_data.at(TypeOffset)); +} + +QByteArray AbstractSshPacket::payLoad() const +{ + return QByteArray(m_data.constData() + PayloadOffset, + length() - paddingLength() - 1); +} + +void AbstractSshPacket::printRawBytes() const +{ + printByteArray(m_data); +} + +QByteArray AbstractSshPacket::encodeString(const QByteArray &string) +{ + QByteArray data; + data.resize(4); + data += string; + setLengthField(data); + return data; +} + +QByteArray AbstractSshPacket::encodeMpInt(const Botan::BigInt &number) +{ + if (number.is_zero()) + return QByteArray(4, 0); + + int stringLength = static_cast(number.bytes()); + const bool positiveAndMsbSet = number.sign() == Botan::BigInt::Positive + && (number.byte_at(stringLength - 1) & 0x80); + if (positiveAndMsbSet) + ++stringLength; + QByteArray data; + data.resize(4 + stringLength); + int pos = 4; + if (positiveAndMsbSet) + data[pos++] = '\0'; + number.binary_encode(reinterpret_cast(data.data()) + pos); + setLengthField(data); + return data; +} + +int AbstractSshPacket::paddingLength() const +{ + return m_data[PaddingLengthOffset]; +} + +quint32 AbstractSshPacket::length() const +{ + //Q_ASSERT(currentDataSize() >= minPacketSize()); + if (m_length == 0) + calculateLength(); + return m_length; +} + +void AbstractSshPacket::calculateLength() const +{ + m_length = SshPacketParser::asUint32(m_data, static_cast(0)); +} + +QByteArray AbstractSshPacket::generateMac(const SshAbstractCryptoFacility &crypt, + quint32 seqNr) const +{ + const quint32 seqNrBe = qToBigEndian(seqNr); + QByteArray data(reinterpret_cast(&seqNrBe), sizeof seqNrBe); + data += QByteArray(m_data.constData(), length() + 4); + return crypt.generateMac(data, data.size()); +} + +quint32 AbstractSshPacket::minPacketSize() const +{ + return qMax(cipherBlockSize(), 16) + macLength(); +} + +void AbstractSshPacket::setLengthField(QByteArray &data) +{ + const quint32 length = qToBigEndian(data.size() - 4); + data.replace(0, 4, reinterpret_cast(&length), 4); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshpacket_p.h b/client/3rd/QtSsh/src/ssh/sshpacket_p.h new file mode 100644 index 00000000..4a94a432 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshpacket_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshexception_p.h" + +#include +#include +#include + +namespace Botan { class BigInt; } + +namespace QSsh { +namespace Internal { + +enum SshPacketType { + SSH_MSG_DISCONNECT = 1, + SSH_MSG_IGNORE = 2, + SSH_MSG_UNIMPLEMENTED = 3, + SSH_MSG_DEBUG = 4, + SSH_MSG_SERVICE_REQUEST = 5, + SSH_MSG_SERVICE_ACCEPT = 6, + + SSH_MSG_KEXINIT = 20, + SSH_MSG_NEWKEYS = 21, + SSH_MSG_KEXDH_INIT = 30, + SSH_MSG_KEX_ECDH_INIT = 30, + SSH_MSG_KEXDH_REPLY = 31, + SSH_MSG_KEX_ECDH_REPLY = 31, + + SSH_MSG_USERAUTH_REQUEST = 50, + SSH_MSG_USERAUTH_FAILURE = 51, + SSH_MSG_USERAUTH_SUCCESS = 52, + SSH_MSG_USERAUTH_BANNER = 53, + SSH_MSG_USERAUTH_PK_OK = 60, + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60, + SSH_MSG_USERAUTH_INFO_REQUEST = 60, + SSH_MSG_USERAUTH_INFO_RESPONSE = 61, + + SSH_MSG_GLOBAL_REQUEST = 80, + SSH_MSG_REQUEST_SUCCESS = 81, + SSH_MSG_REQUEST_FAILURE = 82, + + // TODO: We currently take no precautions against sending these messages + // during a key re-exchange, which is not allowed. + SSH_MSG_CHANNEL_OPEN = 90, + SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91, + SSH_MSG_CHANNEL_OPEN_FAILURE = 92, + SSH_MSG_CHANNEL_WINDOW_ADJUST = 93, + SSH_MSG_CHANNEL_DATA = 94, + SSH_MSG_CHANNEL_EXTENDED_DATA = 95, + SSH_MSG_CHANNEL_EOF = 96, + SSH_MSG_CHANNEL_CLOSE = 97, + SSH_MSG_CHANNEL_REQUEST = 98, + SSH_MSG_CHANNEL_SUCCESS = 99, + SSH_MSG_CHANNEL_FAILURE = 100, + + // Not completely safe, since the server may actually understand this + // message type as an extension. Switch to a different value in that case + // (between 128 and 191). + SSH_MSG_INVALID = 128 +}; + +enum SshOpenFailureType { + SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1, + SSH_OPEN_CONNECT_FAILED = 2, + SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3, + SSH_OPEN_RESOURCE_SHORTAGE = 4 +}; + +enum SshExtendedDataType { SSH_EXTENDED_DATA_STDERR = 1 }; + +class SshAbstractCryptoFacility; + +class AbstractSshPacket +{ +public: + virtual ~AbstractSshPacket(); + + void clear(); + bool isComplete() const; + SshPacketType type() const; + + static QByteArray encodeString(const QByteArray &string); + static QByteArray encodeMpInt(const Botan::BigInt &number); + template static QByteArray encodeInt(T value) + { + const T valMsb = qToBigEndian(value); + return QByteArray(reinterpret_cast(&valMsb), sizeof valMsb); + } + + static void setLengthField(QByteArray &data); + + void printRawBytes() const; // For Debugging. + + const QByteArray &rawData() const { return m_data; } + + QByteArray payLoad() const; + +protected: + AbstractSshPacket(); + + virtual quint32 cipherBlockSize() const = 0; + virtual quint32 macLength() const = 0; + virtual void calculateLength() const; + + quint32 length() const; + int paddingLength() const; + quint32 minPacketSize() const; + quint32 currentDataSize() const { return m_data.size(); } + QByteArray generateMac(const SshAbstractCryptoFacility &crypt, + quint32 seqNr) const; + + static const quint32 PaddingLengthOffset; + static const quint32 PayloadOffset; + static const quint32 TypeOffset; + static const quint32 MinPaddingLength; + + mutable QByteArray m_data; + mutable quint32 m_length; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshpacketparser.cpp b/client/3rd/QtSsh/src/ssh/sshpacketparser.cpp new file mode 100644 index 00000000..38f9c5a0 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshpacketparser.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshpacketparser_p.h" + +#include + +namespace QSsh { +namespace Internal { + +namespace { quint32 size(const QByteArray &data) { return data.size(); } } + +QString SshPacketParser::asUserString(const QByteArray &rawString) +{ + QByteArray filteredString; + filteredString.resize(rawString.size()); + for (int i = 0; i < rawString.size(); ++i) { + const char c = rawString.at(i); + filteredString[i] + = std::isprint(c) || c == '\n' || c == '\r' || c == '\t' ? c : '?'; + } + return QString::fromUtf8(filteredString); +} + +bool SshPacketParser::asBool(const QByteArray &data, quint32 offset) +{ + if (size(data) <= offset) + throw SshPacketParseException(); + return data.at(offset); +} + +bool SshPacketParser::asBool(const QByteArray &data, quint32 *offset) +{ + bool b = asBool(data, *offset); + ++(*offset); + return b; +} + + +quint32 SshPacketParser::asUint32(const QByteArray &data, quint32 offset) +{ + if (size(data) < offset + 4) + throw SshPacketParseException(); + const quint32 value = ((data.at(offset) & 0xff) << 24) + + ((data.at(offset + 1) & 0xff) << 16) + + ((data.at(offset + 2) & 0xff) << 8) + (data.at(offset + 3) & 0xff); + return value; +} + +quint32 SshPacketParser::asUint32(const QByteArray &data, quint32 *offset) +{ + const quint32 v = asUint32(data, *offset); + *offset += 4; + return v; +} + +quint64 SshPacketParser::asUint64(const QByteArray &data, quint32 offset) +{ + if (size(data) < offset + 8) + throw SshPacketParseException(); + const quint64 value = (static_cast(data.at(offset) & 0xff) << 56) + + (static_cast(data.at(offset + 1) & 0xff) << 48) + + (static_cast(data.at(offset + 2) & 0xff) << 40) + + (static_cast(data.at(offset + 3) & 0xff) << 32) + + ((data.at(offset + 4) & 0xff) << 24) + + ((data.at(offset + 5) & 0xff) << 16) + + ((data.at(offset + 6) & 0xff) << 8) + + (data.at(offset + 7) & 0xff); + return value; +} + +quint64 SshPacketParser::asUint64(const QByteArray &data, quint32 *offset) +{ + const quint64 val = asUint64(data, *offset); + *offset += 8; + return val; +} + +QByteArray SshPacketParser::asString(const QByteArray &data, quint32 *offset) +{ + const quint32 length = asUint32(data, offset); + if (size(data) < *offset + length) + throw SshPacketParseException(); + const QByteArray &string = data.mid(*offset, length); + *offset += length; + return string; +} + +QString SshPacketParser::asUserString(const QByteArray &data, quint32 *offset) +{ + return asUserString(asString(data, offset)); +} + +SshNameList SshPacketParser::asNameList(const QByteArray &data, quint32 *offset) +{ + const quint32 length = asUint32(data, offset); + const int listEndPos = *offset + length; + if (data.size() < listEndPos) + throw SshPacketParseException(); + SshNameList names(length + 4); + int nextNameOffset = *offset; + int nextCommaOffset = data.indexOf(',', nextNameOffset); + while (nextNameOffset > 0 && nextNameOffset < listEndPos) { + const int stringEndPos = nextCommaOffset == -1 + || nextCommaOffset > listEndPos ? listEndPos : nextCommaOffset; + names.names << QByteArray(data.constData() + nextNameOffset, + stringEndPos - nextNameOffset); + nextNameOffset = nextCommaOffset + 1; + nextCommaOffset = data.indexOf(',', nextNameOffset); + } + *offset += length; + return names; +} + +Botan::BigInt SshPacketParser::asBigInt(const QByteArray &data, quint32 *offset) +{ + const quint32 length = asUint32(data, offset); + if (length == 0) + return Botan::BigInt(); + const Botan::byte *numberStart + = reinterpret_cast(data.constData() + *offset); + *offset += length; + return Botan::BigInt::decode(numberStart, length); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshpacketparser_p.h b/client/3rd/QtSsh/src/ssh/sshpacketparser_p.h new file mode 100644 index 00000000..8dd70511 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshpacketparser_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include +#include + +namespace QSsh { +namespace Internal { + +struct SshNameList +{ + SshNameList() : originalLength(0) {} + SshNameList(quint32 originalLength) : originalLength(originalLength) {} + quint32 originalLength; + QList names; +}; + +class SshPacketParseException { }; + +// This class's functions try to read a byte array at a certain offset +// as the respective chunk of data as specified in the SSH RFCs. +// If they succeed, they update the offset, so they can easily +// be called in succession by client code. +// For convenience, some have also versions that don't update the offset, +// so they can be called with rvalues if the new value is not needed. +// If they fail, they throw an SshPacketParseException. +class SshPacketParser +{ +public: + static bool asBool(const QByteArray &data, quint32 offset); + static bool asBool(const QByteArray &data, quint32 *offset); + static quint16 asUint16(const QByteArray &data, quint32 offset); + static quint16 asUint16(const QByteArray &data, quint32 *offset); + static quint64 asUint64(const QByteArray &data, quint32 offset); + static quint64 asUint64(const QByteArray &data, quint32 *offset); + static quint32 asUint32(const QByteArray &data, quint32 offset); + static quint32 asUint32(const QByteArray &data, quint32 *offset); + static QByteArray asString(const QByteArray &data, quint32 *offset); + static QString asUserString(const QByteArray &data, quint32 *offset); + static SshNameList asNameList(const QByteArray &data, quint32 *offset); + static Botan::BigInt asBigInt(const QByteArray &data, quint32 *offset); + + static QString asUserString(const QByteArray &rawString); +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshpseudoterminal.h b/client/3rd/QtSsh/src/ssh/sshpseudoterminal.h new file mode 100644 index 00000000..827d6449 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshpseudoterminal.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include +#include + +namespace QSsh { + +class QSSH_EXPORT SshPseudoTerminal +{ + public: + explicit SshPseudoTerminal(const QByteArray &termType = "vt100", + int rowCount = 24, int columnCount = 80) + : termType(termType), rowCount(rowCount), columnCount(columnCount) {} + + QByteArray termType; + int rowCount; + int columnCount; + + enum Mode { + VINTR = 1, // Interrupt character. + VQUIT = 2, // The quit character (sends SIGQUIT signal on POSIX systems). + VERASE = 3, // Erase the character to left of the cursor. + VKILL = 4, // Kill the current input line. + VEOF = 5, // End-of-file character (sends EOF from the terminal). + VEOL = 6, // End-of-line character in addition to carriage return and/or linefeed. + VEOL2 = 7, // Additional end-of-line character. + VSTART = 8, // Continues paused output (normally control-Q). + VSTOP = 9, // Pauses output (normally control-S). + VSUSP = 10, // Suspends the current program. + VDSUSP = 11, // Another suspend character. + VREPRINT = 12, // Reprints the current input line. + VWERASE = 13, // Erases a word left of cursor. + VLNEXT = 14, // Enter the next character typed literally, even if it is a special character. + VFLUSH = 15, // Character to flush output. + VSWTCH = 16, // Switch to a different shell layer. + VSTATUS = 17, // Prints system status line (load, command, pid, etc). + VDISCARD = 18, // Toggles the flushing of terminal output. + + IGNPAR = 30, // The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE, and 1 if it is TRUE. + PARMRK = 31, // Mark parity and framing errors. + INPCK = 32, // Enable checking of parity errors. + ISTRIP = 33, // Strip 8th bit off characters. + INLCR = 34, // Map NL into CR on input. + IGNCR = 35, // Ignore CR on input. + ICRNL = 36, // Map CR to NL on input. + IUCLC = 37, // Translate uppercase characters to lowercase. + IXON = 38, // Enable output flow control. + IXANY = 39, // Any char will restart after stop. + IXOFF = 40, // Enable input flow control. + IMAXBEL = 41, // Ring bell on input queue full. + ISIG = 50, // Enable signals INTR, QUIT, [D]SUSP. + ICANON = 51, // Canonicalize input lines. + XCASE = 52, // Enable input and output of uppercase characters by preceding their lowercase equivalents with "\". + ECHO = 53, // Enable echoing. + ECHOE = 54, // Visually erase chars. + ECHOK = 55, // Kill character discards current line. + ECHONL = 56, // Echo NL even if ECHO is off. + NOFLSH = 57, // Don't flush after interrupt. + TOSTOP = 58, // Stop background jobs from output. + IEXTEN = 59, // Enable extensions. + ECHOCTL = 60, // Echo control characters as ^(Char). + ECHOKE = 61, // Visual erase for line kill. + PENDIN = 62, // Retype pending input. + OPOST = 70, // Enable output processing. + OLCUC = 71, // Convert lowercase to uppercase. + ONLCR = 72, // Map NL to CR-NL. + OCRNL = 73, // Translate carriage return to newline (output). + ONOCR = 74, // Translate newline to carriage return-newline (output). + ONLRET = 75, // Newline performs a carriage return (output). + CS7 = 90, // 7 bit mode. + CS8 = 91, // 8 bit mode. + PARENB = 92, // Parity enable. + PARODD = 93, // Odd parity, else even. + + TTY_OP_ISPEED = 128, // Specifies the input baud rate in bits per second. + TTY_OP_OSPEED = 129 // Specifies the output baud rate in bits per second. + }; + + typedef QHash ModeMap; + ModeMap modes; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshremoteprocess.cpp b/client/3rd/QtSsh/src/ssh/sshremoteprocess.cpp new file mode 100644 index 00000000..5a875d1f --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshremoteprocess.cpp @@ -0,0 +1,380 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshremoteprocess.h" +#include "sshremoteprocess_p.h" + +#include "ssh_global.h" +#include "sshincomingpacket_p.h" +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +#include + +#include + +#include +#include + +/*! + \class QSsh::SshRemoteProcess + + \brief The SshRemoteProcess class implements an SSH channel for running a + remote process. + + Objects are created via SshConnection::createRemoteProcess. + The process is started via the start() member function. + If the process needs a pseudo terminal, you can request one + via requestTerminal() before calling start(). + Note that this class does not support QIODevice's waitFor*() functions, i.e. it has + no synchronous mode. + */ + +namespace QSsh { + +const struct { + SshRemoteProcess::Signal signalEnum; + const char * const signalString; +} signalMap[] = { + {SshRemoteProcess::AbrtSignal, "ABRT"}, {SshRemoteProcess::AlrmSignal, "ALRM"}, + {SshRemoteProcess::FpeSignal, "FPE"}, {SshRemoteProcess::HupSignal, "HUP"}, + {SshRemoteProcess::IllSignal, "ILL"}, {SshRemoteProcess::IntSignal, "INT"}, + {SshRemoteProcess::KillSignal, "KILL"}, {SshRemoteProcess::PipeSignal, "PIPE"}, + {SshRemoteProcess::QuitSignal, "QUIT"}, {SshRemoteProcess::SegvSignal, "SEGV"}, + {SshRemoteProcess::TermSignal, "TERM"}, {SshRemoteProcess::Usr1Signal, "USR1"}, + {SshRemoteProcess::Usr2Signal, "USR2"} +}; + +SshRemoteProcess::SshRemoteProcess(const QByteArray &command, quint32 channelId, + Internal::SshSendFacility &sendFacility) + : d(new Internal::SshRemoteProcessPrivate(command, channelId, sendFacility, this)) +{ + init(); +} + +SshRemoteProcess::SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility) + : d(new Internal::SshRemoteProcessPrivate(channelId, sendFacility, this)) +{ + init(); +} + +SshRemoteProcess::~SshRemoteProcess() +{ + QSSH_ASSERT(d->channelState() != Internal::AbstractSshChannel::SessionEstablished); + close(); + delete d; +} + +bool SshRemoteProcess::atEnd() const +{ + return QIODevice::atEnd() && d->data().isEmpty(); +} + +qint64 SshRemoteProcess::bytesAvailable() const +{ + return QIODevice::bytesAvailable() + d->data().count(); +} + +bool SshRemoteProcess::canReadLine() const +{ + return QIODevice::canReadLine() || d->data().contains('\n'); +} + +QByteArray SshRemoteProcess::readAllStandardOutput() +{ + return readAllFromChannel(QProcess::StandardOutput); +} + +QByteArray SshRemoteProcess::readAllStandardError() +{ + return readAllFromChannel(QProcess::StandardError); +} + +QByteArray SshRemoteProcess::readAllFromChannel(QProcess::ProcessChannel channel) +{ + const QProcess::ProcessChannel currentReadChannel = readChannel(); + setReadChannel(channel); + const QByteArray &data = readAll(); + setReadChannel(currentReadChannel); + return data; +} + +void SshRemoteProcess::close() +{ + d->closeChannel(); + QIODevice::close(); +} + +qint64 SshRemoteProcess::readData(char *data, qint64 maxlen) +{ + const qint64 bytesRead = qMin(qint64(d->data().count()), maxlen); + memcpy(data, d->data().constData(), bytesRead); + d->data().remove(0, bytesRead); + return bytesRead; +} + +qint64 SshRemoteProcess::writeData(const char *data, qint64 len) +{ + if (isRunning()) { + d->sendData(QByteArray(data, len)); + return len; + } + return 0; +} + +QProcess::ProcessChannel SshRemoteProcess::readChannel() const +{ + return d->m_readChannel; +} + +void SshRemoteProcess::setReadChannel(QProcess::ProcessChannel channel) +{ + d->m_readChannel = channel; +} + +void SshRemoteProcess::init() +{ + connect(d, &Internal::SshRemoteProcessPrivate::started, + this, &SshRemoteProcess::started, Qt::QueuedConnection); + connect(d, &Internal::SshRemoteProcessPrivate::readyReadStandardOutput, + this, &SshRemoteProcess::readyReadStandardOutput, Qt::QueuedConnection); + connect(d, &Internal::SshRemoteProcessPrivate::readyRead, + this, &SshRemoteProcess::readyRead, Qt::QueuedConnection); + connect(d, &Internal::SshRemoteProcessPrivate::readyReadStandardError, + this, &SshRemoteProcess::readyReadStandardError, Qt::QueuedConnection); + connect(d, &Internal::SshRemoteProcessPrivate::closed, + this, &SshRemoteProcess::closed, Qt::QueuedConnection); + connect(d, &Internal::SshRemoteProcessPrivate::eof, + this, &SshRemoteProcess::readChannelFinished, Qt::QueuedConnection); +} + +void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray &value) +{ + if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive) + d->m_env << qMakePair(var, value); // Cached locally and sent on start() +} + +void SshRemoteProcess::clearEnvironment() +{ + d->m_env.clear(); +} + +void SshRemoteProcess::requestTerminal(const SshPseudoTerminal &terminal) +{ + QSSH_ASSERT_AND_RETURN(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive); + d->m_useTerminal = true; + d->m_terminal = terminal; +} + +void SshRemoteProcess::start() +{ + if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive) { + qCDebug(Internal::sshLog, "process start requested, channel id = %u", d->localChannelId()); + QIODevice::open(QIODevice::ReadWrite); + d->requestSessionStart(); + } +} + +void SshRemoteProcess::sendSignal(Signal signal) +{ + try { + if (isRunning()) { + const char *signalString = 0; + for (size_t i = 0; i < sizeof signalMap/sizeof *signalMap && !signalString; ++i) { + if (signalMap[i].signalEnum == signal) + signalString = signalMap[i].signalString; + } + QSSH_ASSERT_AND_RETURN(signalString); + d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), signalString); + } + } catch (const std::exception &e) { + setErrorString(QString::fromLatin1(e.what())); + d->closeChannel(); + } +} + +bool SshRemoteProcess::isRunning() const +{ + return d->m_procState == Internal::SshRemoteProcessPrivate::Running; +} + +int SshRemoteProcess::exitCode() const { return d->m_exitCode; } + +SshRemoteProcess::Signal SshRemoteProcess::exitSignal() const +{ + return static_cast(d->m_signal); +} + +namespace Internal { + +SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command, + quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc) + : AbstractSshChannel(channelId, sendFacility), + m_command(command), + m_isShell(false), + m_useTerminal(false), + m_proc(proc) +{ + init(); +} + +SshRemoteProcessPrivate::SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility, + SshRemoteProcess *proc) + : AbstractSshChannel(channelId, sendFacility), + m_isShell(true), + m_useTerminal(true), + m_proc(proc) +{ + init(); +} + +void SshRemoteProcessPrivate::init() +{ + m_procState = NotYetStarted; + m_wasRunning = false; + m_exitCode = 0; + m_readChannel = QProcess::StandardOutput; + m_signal = SshRemoteProcess::NoSignal; +} + +void SshRemoteProcessPrivate::setProcState(ProcessState newState) +{ + qCDebug(sshLog, "channel: old state = %d,new state = %d", m_procState, newState); + m_procState = newState; + if (newState == StartFailed) { + emit closed(SshRemoteProcess::FailedToStart); + } else if (newState == Running) { + m_wasRunning = true; + emit started(); + } +} + +QByteArray &SshRemoteProcessPrivate::data() +{ + return m_readChannel == QProcess::StandardOutput ? m_stdout : m_stderr; +} + +void SshRemoteProcessPrivate::closeHook() +{ + if (m_wasRunning) { + if (m_signal != SshRemoteProcess::NoSignal) + emit closed(SshRemoteProcess::CrashExit); + else + emit closed(SshRemoteProcess::NormalExit); + } +} + +void SshRemoteProcessPrivate::handleOpenSuccessInternal() +{ + foreach (const EnvVar &envVar, m_env) { + m_sendFacility.sendEnvPacket(remoteChannel(), envVar.first, + envVar.second); + } + + if (m_useTerminal) + m_sendFacility.sendPtyRequestPacket(remoteChannel(), m_terminal); + + if (m_isShell) + m_sendFacility.sendShellPacket(remoteChannel()); + else + m_sendFacility.sendExecPacket(remoteChannel(), m_command); + setProcState(ExecRequested); + m_timeoutTimer.start(ReplyTimeout); +} + +void SshRemoteProcessPrivate::handleOpenFailureInternal(const QString &reason) +{ + setProcState(StartFailed); + m_proc->setErrorString(reason); +} + +void SshRemoteProcessPrivate::handleChannelSuccess() +{ + if (m_procState != ExecRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_SUCCESS message."); + } + m_timeoutTimer.stop(); + setProcState(Running); +} + +void SshRemoteProcessPrivate::handleChannelFailure() +{ + if (m_procState != ExecRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_FAILURE message."); + } + m_timeoutTimer.stop(); + setProcState(StartFailed); + closeChannel(); +} + +void SshRemoteProcessPrivate::handleChannelDataInternal(const QByteArray &data) +{ + m_stdout += data; + emit readyReadStandardOutput(); + if (m_readChannel == QProcess::StandardOutput) + emit readyRead(); +} + +void SshRemoteProcessPrivate::handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data) +{ + if (type != SSH_EXTENDED_DATA_STDERR) { + qCWarning(sshLog, "Unknown extended data type %u", type); + } else { + m_stderr += data; + emit readyReadStandardError(); + if (m_readChannel == QProcess::StandardError) + emit readyRead(); + } +} + +void SshRemoteProcessPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) +{ + qCDebug(sshLog, "Process exiting with exit code %d", exitStatus.exitStatus); + m_exitCode = exitStatus.exitStatus; + m_procState = Exited; +} + +void SshRemoteProcessPrivate::handleExitSignal(const SshChannelExitSignal &signal) +{ + qCDebug(sshLog, "Exit due to signal %s", signal.signal.data()); + + for (size_t i = 0; i < sizeof signalMap/sizeof *signalMap; ++i) { + if (signalMap[i].signalString == signal.signal) { + m_signal = signalMap[i].signalEnum; + m_procState = Exited; + m_proc->setErrorString(tr("Process killed by signal")); + return; + } + } + + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid signal", + tr("Server sent invalid signal \"%1\"").arg(QString::fromUtf8(signal.signal))); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshremoteprocess.h b/client/3rd/QtSsh/src/ssh/sshremoteprocess.h new file mode 100644 index 00000000..cd54a03e --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshremoteprocess.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" + +#include +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +QT_END_NAMESPACE + +namespace QSsh { +class SshPseudoTerminal; +namespace Internal { +class SshChannelManager; +class SshRemoteProcessPrivate; +class SshSendFacility; +} // namespace Internal + +// TODO: ProcessChannel +class QSSH_EXPORT SshRemoteProcess : public QIODevice +{ + Q_OBJECT + + friend class Internal::SshChannelManager; + friend class Internal::SshRemoteProcessPrivate; + +public: + typedef QSharedPointer Ptr; + enum ExitStatus { FailedToStart, CrashExit, NormalExit }; + enum Signal { + AbrtSignal, AlrmSignal, FpeSignal, HupSignal, IllSignal, IntSignal, KillSignal, PipeSignal, + QuitSignal, SegvSignal, TermSignal, Usr1Signal, Usr2Signal, NoSignal + }; + + ~SshRemoteProcess(); + + // QIODevice stuff + bool atEnd() const; + qint64 bytesAvailable() const; + bool canReadLine() const; + void close(); + bool isSequential() const { return true; } + + QProcess::ProcessChannel readChannel() const; + void setReadChannel(QProcess::ProcessChannel channel); + + /* + * Note that this is of limited value in practice, because servers are + * usually configured to ignore such requests for security reasons. + */ + void addToEnvironment(const QByteArray &var, const QByteArray &value); + void clearEnvironment(); + + void requestTerminal(const SshPseudoTerminal &terminal); + void start(); + + bool isRunning() const; + int exitCode() const; + Signal exitSignal() const; + + QByteArray readAllStandardOutput(); + QByteArray readAllStandardError(); + + // Note: This is ignored by the OpenSSH server. + void sendSignal(Signal signal); + void kill() { sendSignal(KillSignal); } + +signals: + void started(); + + void readyReadStandardOutput(); + void readyReadStandardError(); + + /* + * Parameter is of type ExitStatus, but we use int because of + * signal/slot awkwardness (full namespace required). + */ + void closed(int exitStatus); + +private: + SshRemoteProcess(const QByteArray &command, quint32 channelId, + Internal::SshSendFacility &sendFacility); + SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility); + + // QIODevice stuff + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + void init(); + QByteArray readAllFromChannel(QProcess::ProcessChannel channel); + + Internal::SshRemoteProcessPrivate *d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshremoteprocess_p.h b/client/3rd/QtSsh/src/ssh/sshremoteprocess_p.h new file mode 100644 index 00000000..edf06483 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshremoteprocess_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshpseudoterminal.h" + +#include "sshchannel_p.h" + +#include +#include +#include + +namespace QSsh { +class SshRemoteProcess; + +namespace Internal { +class SshSendFacility; + +class SshRemoteProcessPrivate : public AbstractSshChannel +{ + Q_OBJECT + friend class QSsh::SshRemoteProcess; +public: + enum ProcessState { + NotYetStarted, ExecRequested, StartFailed, Running, Exited + }; + +signals: + void started(); + void readyRead(); + void readyReadStandardOutput(); + void readyReadStandardError(); + void closed(int exitStatus); + +private: + SshRemoteProcessPrivate(const QByteArray &command, quint32 channelId, + SshSendFacility &sendFacility, SshRemoteProcess *proc); + SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility, + SshRemoteProcess *proc); + + virtual void handleChannelSuccess(); + virtual void handleChannelFailure(); + + virtual void handleOpenSuccessInternal(); + virtual void handleOpenFailureInternal(const QString &reason); + virtual void handleChannelDataInternal(const QByteArray &data); + virtual void handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data); + virtual void handleExitStatus(const SshChannelExitStatus &exitStatus); + virtual void handleExitSignal(const SshChannelExitSignal &signal); + + virtual void closeHook(); + + void init(); + void setProcState(ProcessState newState); + QByteArray &data(); + + QProcess::ProcessChannel m_readChannel; + + ProcessState m_procState; + bool m_wasRunning; + int m_signal; + int m_exitCode; + + const QByteArray m_command; + const bool m_isShell; + + typedef QPair EnvVar; + QList m_env; + bool m_useTerminal; + SshPseudoTerminal m_terminal; + + QByteArray m_stdout; + QByteArray m_stderr; + + SshRemoteProcess *m_proc; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.cpp b/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.cpp new file mode 100644 index 00000000..b3f55257 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.cpp @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshremoteprocessrunner.h" + +#include "sshconnectionmanager.h" +#include "sshpseudoterminal.h" + + +/*! + \class QSsh::SshRemoteProcessRunner + + \brief The SshRemoteProcessRunner class is a convenience class for + running a remote process over an SSH connection. +*/ + +namespace QSsh { +namespace Internal { +namespace { +enum State { Inactive, Connecting, Connected, ProcessRunning }; +} // anonymous namespace + +class SshRemoteProcessRunnerPrivate +{ +public: + SshRemoteProcessRunnerPrivate() : m_state(Inactive) {} + + SshRemoteProcess::Ptr m_process; + SshConnection *m_connection; + bool m_runInTerminal; + SshPseudoTerminal m_terminal; + QByteArray m_command; + QSsh::SshError m_lastConnectionError; + QString m_lastConnectionErrorString; + SshRemoteProcess::ExitStatus m_exitStatus; + SshRemoteProcess::Signal m_exitSignal; + QByteArray m_stdout; + QByteArray m_stderr; + int m_exitCode; + QString m_processErrorString; + State m_state; +}; + +} // namespace Internal + +using namespace Internal; + +SshRemoteProcessRunner::SshRemoteProcessRunner(QObject *parent) + : QObject(parent), d(new SshRemoteProcessRunnerPrivate) +{ +} + +SshRemoteProcessRunner::~SshRemoteProcessRunner() +{ + disconnect(); + setState(Inactive); + delete d; +} + +void SshRemoteProcessRunner::run(const QByteArray &command, + const SshConnectionParameters &sshParams) +{ + QSSH_ASSERT_AND_RETURN(d->m_state == Inactive); + + d->m_runInTerminal = false; + runInternal(command, sshParams); +} + +void SshRemoteProcessRunner::runInTerminal(const QByteArray &command, + const SshPseudoTerminal &terminal, const SshConnectionParameters &sshParams) +{ + d->m_terminal = terminal; + d->m_runInTerminal = true; + runInternal(command, sshParams); +} + +void SshRemoteProcessRunner::runInternal(const QByteArray &command, + const SshConnectionParameters &sshParams) +{ + setState(Connecting); + + d->m_lastConnectionError = SshNoError; + d->m_lastConnectionErrorString.clear(); + d->m_processErrorString.clear(); + d->m_exitSignal = SshRemoteProcess::NoSignal; + d->m_exitCode = -1; + d->m_command = command; + d->m_connection = QSsh::acquireConnection(sshParams); + connect(d->m_connection, &SshConnection::error, + this, &SshRemoteProcessRunner::handleConnectionError); + connect(d->m_connection, &SshConnection::disconnected, + this, &SshRemoteProcessRunner::handleDisconnected); + if (d->m_connection->state() == SshConnection::Connected) { + handleConnected(); + } else { + connect(d->m_connection, &SshConnection::connected, this, &SshRemoteProcessRunner::handleConnected); + if (d->m_connection->state() == SshConnection::Unconnected) + d->m_connection->connectToHost(); + } +} + +void SshRemoteProcessRunner::handleConnected() +{ + QSSH_ASSERT_AND_RETURN(d->m_state == Connecting); + setState(Connected); + + d->m_process = d->m_connection->createRemoteProcess(d->m_command); + connect(d->m_process.data(), &SshRemoteProcess::started, + this, &SshRemoteProcessRunner::handleProcessStarted); + connect(d->m_process.data(), &SshRemoteProcess::closed, + this, &SshRemoteProcessRunner::handleProcessFinished); + connect(d->m_process.data(), &SshRemoteProcess::readyReadStandardOutput, + this, &SshRemoteProcessRunner::handleStdout); + connect(d->m_process.data(), &SshRemoteProcess::readyReadStandardError, + this, &SshRemoteProcessRunner::handleStderr); + if (d->m_runInTerminal) + d->m_process->requestTerminal(d->m_terminal); + d->m_process->start(); +} + +void SshRemoteProcessRunner::handleConnectionError(QSsh::SshError error) +{ + d->m_lastConnectionError = error; + d->m_lastConnectionErrorString = d->m_connection->errorString(); + handleDisconnected(); + emit connectionError(); +} + +void SshRemoteProcessRunner::handleDisconnected() +{ + QSSH_ASSERT_AND_RETURN(d->m_state == Connecting || d->m_state == Connected + || d->m_state == ProcessRunning); + setState(Inactive); +} + +void SshRemoteProcessRunner::handleProcessStarted() +{ + QSSH_ASSERT_AND_RETURN(d->m_state == Connected); + + setState(ProcessRunning); + emit processStarted(); +} + +void SshRemoteProcessRunner::handleProcessFinished(int exitStatus) +{ + d->m_exitStatus = static_cast(exitStatus); + switch (d->m_exitStatus) { + case SshRemoteProcess::FailedToStart: + QSSH_ASSERT_AND_RETURN(d->m_state == Connected); + break; + case SshRemoteProcess::CrashExit: + QSSH_ASSERT_AND_RETURN(d->m_state == ProcessRunning); + d->m_exitSignal = d->m_process->exitSignal(); + break; + case SshRemoteProcess::NormalExit: + QSSH_ASSERT_AND_RETURN(d->m_state == ProcessRunning); + d->m_exitCode = d->m_process->exitCode(); + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status."); + } + d->m_processErrorString = d->m_process->errorString(); + setState(Inactive); + emit processClosed(exitStatus); +} + +void SshRemoteProcessRunner::handleStdout() +{ + d->m_stdout += d->m_process->readAllStandardOutput(); + emit readyReadStandardOutput(); +} + +void SshRemoteProcessRunner::handleStderr() +{ + d->m_stderr += d->m_process->readAllStandardError(); + emit readyReadStandardError(); +} + +void SshRemoteProcessRunner::setState(int newState) +{ + if (d->m_state == newState) + return; + + d->m_state = static_cast(newState); + if (d->m_state == Inactive) { + if (d->m_process) { + disconnect(d->m_process.data(), 0, this, 0); + d->m_process->close(); + d->m_process.clear(); + } + if (d->m_connection) { + disconnect(d->m_connection, 0, this, 0); + QSsh::releaseConnection(d->m_connection); + d->m_connection = 0; + } + } +} + +QByteArray SshRemoteProcessRunner::command() const { return d->m_command; } +SshError SshRemoteProcessRunner::lastConnectionError() const { return d->m_lastConnectionError; } +QString SshRemoteProcessRunner::lastConnectionErrorString() const { + return d->m_lastConnectionErrorString; +} + +bool SshRemoteProcessRunner::isProcessRunning() const +{ + return d->m_process && d->m_process->isRunning(); +} + +SshRemoteProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const +{ + QSSH_ASSERT(!isProcessRunning()); + return d->m_exitStatus; +} + +SshRemoteProcess::Signal SshRemoteProcessRunner::processExitSignal() const +{ + QSSH_ASSERT(processExitStatus() == SshRemoteProcess::CrashExit); + return d->m_exitSignal; +} + +int SshRemoteProcessRunner::processExitCode() const +{ + QSSH_ASSERT(processExitStatus() == SshRemoteProcess::NormalExit); + return d->m_exitCode; +} + +QString SshRemoteProcessRunner::processErrorString() const +{ + return d->m_processErrorString; +} + +QByteArray SshRemoteProcessRunner::readAllStandardOutput() +{ + const QByteArray data = d->m_stdout; + d->m_stdout.clear(); + return data; +} + +QByteArray SshRemoteProcessRunner::readAllStandardError() +{ + const QByteArray data = d->m_stderr; + d->m_stderr.clear(); + return data; +} + +void SshRemoteProcessRunner::writeDataToProcess(const QByteArray &data) +{ + QSSH_ASSERT(isProcessRunning()); + d->m_process->write(data); +} + +void SshRemoteProcessRunner::sendSignalToProcess(SshRemoteProcess::Signal signal) +{ + QSSH_ASSERT(isProcessRunning()); + d->m_process->sendSignal(signal); +} + +void SshRemoteProcessRunner::cancel() +{ + setState(Inactive); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.h b/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.h new file mode 100644 index 00000000..0a2ee578 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshremoteprocessrunner.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshconnection.h" +#include "sshremoteprocess.h" + +namespace QSsh { +namespace Internal { class SshRemoteProcessRunnerPrivate; } + +class QSSH_EXPORT SshRemoteProcessRunner : public QObject +{ + Q_OBJECT + +public: + SshRemoteProcessRunner(QObject *parent = 0); + ~SshRemoteProcessRunner(); + + void run(const QByteArray &command, const SshConnectionParameters &sshParams); + void runInTerminal(const QByteArray &command, const SshPseudoTerminal &terminal, + const SshConnectionParameters &sshParams); + QByteArray command() const; + + QSsh::SshError lastConnectionError() const; + QString lastConnectionErrorString() const; + + bool isProcessRunning() const; + void writeDataToProcess(const QByteArray &data); + void sendSignalToProcess(SshRemoteProcess::Signal signal); // No effect with OpenSSH server. + void cancel(); // Does not stop remote process, just frees SSH-related process resources. + SshRemoteProcess::ExitStatus processExitStatus() const; + SshRemoteProcess::Signal processExitSignal() const; + int processExitCode() const; + QString processErrorString() const; + QByteArray readAllStandardOutput(); + QByteArray readAllStandardError(); + +signals: + void connectionError(); + void processStarted(); + void readyReadStandardOutput(); + void readyReadStandardError(); + void processClosed(int exitStatus); // values are of type SshRemoteProcess::ExitStatus + +private: + void handleConnected(); + void handleConnectionError(QSsh::SshError error); + void handleDisconnected(); + void handleProcessStarted(); + void handleProcessFinished(int exitStatus); + void handleStdout(); + void handleStderr(); + void runInternal(const QByteArray &command, const QSsh::SshConnectionParameters &sshParams); + void setState(int newState); + + Internal::SshRemoteProcessRunnerPrivate * const d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshsendfacility.cpp b/client/3rd/QtSsh/src/ssh/sshsendfacility.cpp new file mode 100644 index 00000000..491c6981 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshsendfacility.cpp @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshsendfacility_p.h" + +#include "sshkeyexchange_p.h" +#include "sshlogging_p.h" +#include "sshoutgoingpacket_p.h" + +#include + +namespace QSsh { +namespace Internal { + +SshSendFacility::SshSendFacility(QTcpSocket *socket) + : m_clientSeqNr(0), m_socket(socket), + m_outgoingPacket(m_encrypter, m_clientSeqNr) +{ +} + +void SshSendFacility::sendPacket() +{ + qCDebug(sshLog, "Sending packet, client seq nr is %u", m_clientSeqNr); + if (m_socket->isValid() + && m_socket->state() == QAbstractSocket::ConnectedState) { + m_socket->write(m_outgoingPacket.rawData()); + ++m_clientSeqNr; + } +} + +void SshSendFacility::reset() +{ + m_clientSeqNr = 0; + m_encrypter.clearKeys(); +} + +void SshSendFacility::recreateKeys(const SshKeyExchange &keyExchange) +{ + m_encrypter.recreateKeys(keyExchange); +} + +void SshSendFacility::createAuthenticationKey(const QByteArray &privKeyFileContents) +{ + m_encrypter.createAuthenticationKey(privKeyFileContents); +} + +QByteArray SshSendFacility::sendKeyExchangeInitPacket() +{ + const QByteArray &payLoad = m_outgoingPacket.generateKeyExchangeInitPacket(); + sendPacket(); + return payLoad; +} + +void SshSendFacility::sendKeyDhInitPacket(const Botan::BigInt &e) +{ + m_outgoingPacket.generateKeyDhInitPacket(e); + sendPacket(); +} + +void SshSendFacility::sendKeyEcdhInitPacket(const QByteArray &clientQ) +{ + m_outgoingPacket.generateKeyEcdhInitPacket(clientQ); + sendPacket(); +} + +void SshSendFacility::sendNewKeysPacket() +{ + m_outgoingPacket.generateNewKeysPacket(); + sendPacket(); +} + +void SshSendFacility::sendDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString) +{ + m_outgoingPacket.generateDisconnectPacket(reason, reasonString); + sendPacket(); + } + +void SshSendFacility::sendMsgUnimplementedPacket(quint32 serverSeqNr) +{ + m_outgoingPacket.generateMsgUnimplementedPacket(serverSeqNr); + sendPacket(); +} + +void SshSendFacility::sendUserAuthServiceRequestPacket() +{ + m_outgoingPacket.generateUserAuthServiceRequestPacket(); + sendPacket(); +} + +void SshSendFacility::sendUserAuthByPasswordRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd) +{ + m_outgoingPacket.generateUserAuthByPasswordRequestPacket(user, service, pwd); + sendPacket(); + } + +void SshSendFacility::sendUserAuthByPublicKeyRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + m_outgoingPacket.generateUserAuthByPublicKeyRequestPacket(user, service); + sendPacket(); +} + +void SshSendFacility::sendUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + m_outgoingPacket.generateUserAuthByKeyboardInteractiveRequestPacket(user, service); + sendPacket(); +} + +void SshSendFacility::sendUserAuthInfoResponsePacket(const QStringList &responses) +{ + m_outgoingPacket.generateUserAuthInfoResponsePacket(responses); + sendPacket(); +} + +void SshSendFacility::sendRequestFailurePacket() +{ + m_outgoingPacket.generateRequestFailurePacket(); + sendPacket(); +} + +void SshSendFacility::sendIgnorePacket() +{ + m_outgoingPacket.generateIgnorePacket(); + sendPacket(); +} + +void SshSendFacility::sendInvalidPacket() +{ + m_outgoingPacket.generateInvalidMessagePacket(); + sendPacket(); +} + +void SshSendFacility::sendSessionPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize) +{ + m_outgoingPacket.generateSessionPacket(channelId, windowSize, + maxPacketSize); + sendPacket(); +} + +void SshSendFacility::sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort, + const QByteArray &localIpAddress, quint32 localPort) +{ + m_outgoingPacket.generateDirectTcpIpPacket(channelId, windowSize, maxPacketSize, remoteHost, + remotePort, localIpAddress, localPort); + sendPacket(); +} + +void SshSendFacility::sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort) +{ + m_outgoingPacket.generateTcpIpForwardPacket(bindAddress, bindPort); + sendPacket(); +} + +void SshSendFacility::sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort) +{ + m_outgoingPacket.generateCancelTcpIpForwardPacket(bindAddress, bindPort); + sendPacket(); +} + +void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel, + const SshPseudoTerminal &terminal) +{ + m_outgoingPacket.generatePtyRequestPacket(remoteChannel, terminal); + sendPacket(); +} + +void SshSendFacility::sendEnvPacket(quint32 remoteChannel, + const QByteArray &var, const QByteArray &value) +{ + m_outgoingPacket.generateEnvPacket(remoteChannel, var, value); + sendPacket(); +} + +void SshSendFacility::sendExecPacket(quint32 remoteChannel, + const QByteArray &command) +{ + m_outgoingPacket.generateExecPacket(remoteChannel, command); + sendPacket(); +} + +void SshSendFacility::sendShellPacket(quint32 remoteChannel) +{ + m_outgoingPacket.generateShellPacket(remoteChannel); + sendPacket(); +} + +void SshSendFacility::sendSftpPacket(quint32 remoteChannel) +{ + m_outgoingPacket.generateSftpPacket(remoteChannel); + sendPacket(); +} + +void SshSendFacility::sendWindowAdjustPacket(quint32 remoteChannel, + quint32 bytesToAdd) +{ + m_outgoingPacket.generateWindowAdjustPacket(remoteChannel, bytesToAdd); + sendPacket(); +} + +void SshSendFacility::sendChannelDataPacket(quint32 remoteChannel, + const QByteArray &data) +{ + m_outgoingPacket.generateChannelDataPacket(remoteChannel, data); + sendPacket(); +} + +void SshSendFacility::sendChannelSignalPacket(quint32 remoteChannel, + const QByteArray &signalName) +{ + m_outgoingPacket.generateChannelSignalPacket(remoteChannel, signalName); + sendPacket(); +} + +void SshSendFacility::sendChannelEofPacket(quint32 remoteChannel) +{ + m_outgoingPacket.generateChannelEofPacket(remoteChannel); + sendPacket(); +} + +void SshSendFacility::sendChannelClosePacket(quint32 remoteChannel) +{ + m_outgoingPacket.generateChannelClosePacket(remoteChannel); + sendPacket(); +} + +void SshSendFacility::sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel, + quint32 localWindowSize, quint32 maxPacketSize) +{ + m_outgoingPacket.generateChannelOpenConfirmationPacket(remoteChannel, localChannel, + localWindowSize, maxPacketSize); + sendPacket(); +} + +void SshSendFacility::sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason, + const QByteArray &reasonString) +{ + m_outgoingPacket.generateChannelOpenFailurePacket(remoteChannel, reason, reasonString); + sendPacket(); +} + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshsendfacility_p.h b/client/3rd/QtSsh/src/ssh/sshsendfacility_p.h new file mode 100644 index 00000000..0eb92ae0 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshsendfacility_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshcryptofacility_p.h" +#include "sshoutgoingpacket_p.h" + +#include + +QT_BEGIN_NAMESPACE +class QTcpSocket; +QT_END_NAMESPACE + + +namespace QSsh { +class SshPseudoTerminal; + +namespace Internal { +class SshKeyExchange; + +class SshSendFacility +{ +public: + SshSendFacility(QTcpSocket *socket); + void reset(); + void recreateKeys(const SshKeyExchange &keyExchange); + void createAuthenticationKey(const QByteArray &privKeyFileContents); + + QByteArray sendKeyExchangeInitPacket(); + void sendKeyDhInitPacket(const Botan::BigInt &e); + void sendKeyEcdhInitPacket(const QByteArray &clientQ); + void sendNewKeysPacket(); + void sendDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString); + void sendMsgUnimplementedPacket(quint32 serverSeqNr); + void sendUserAuthServiceRequestPacket(); + void sendUserAuthByPasswordRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd); + void sendUserAuthByPublicKeyRequestPacket(const QByteArray &user, + const QByteArray &service); + void sendUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user, + const QByteArray &service); + void sendUserAuthInfoResponsePacket(const QStringList &responses); + void sendRequestFailurePacket(); + void sendIgnorePacket(); + void sendInvalidPacket(); + void sendSessionPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize); + void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize, + const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress, + quint32 localPort); + void sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort); + void sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort); + void sendPtyRequestPacket(quint32 remoteChannel, + const SshPseudoTerminal &terminal); + void sendEnvPacket(quint32 remoteChannel, const QByteArray &var, + const QByteArray &value); + void sendExecPacket(quint32 remoteChannel, const QByteArray &command); + void sendShellPacket(quint32 remoteChannel); + void sendSftpPacket(quint32 remoteChannel); + void sendWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd); + void sendChannelDataPacket(quint32 remoteChannel, const QByteArray &data); + void sendChannelSignalPacket(quint32 remoteChannel, + const QByteArray &signalName); + void sendChannelEofPacket(quint32 remoteChannel); + void sendChannelClosePacket(quint32 remoteChannel); + void sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel, + quint32 localWindowSize, quint32 maxPackeSize); + void sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason, + const QByteArray &reasonString); + quint32 nextClientSeqNr() const { return m_clientSeqNr; } + +private: + void sendPacket(); + + quint32 m_clientSeqNr; + SshEncryptionFacility m_encrypter; + QTcpSocket *m_socket; + SshOutgoingPacket m_outgoingPacket; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.cpp b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.cpp new file mode 100644 index 00000000..5501ea93 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshtcpipforwardserver.h" +#include "sshtcpipforwardserver_p.h" + +#include "sshlogging_p.h" +#include "sshsendfacility_p.h" + +namespace QSsh { +namespace Internal { + +SshTcpIpForwardServerPrivate::SshTcpIpForwardServerPrivate(const QString &bindAddress, + quint16 bindPort, SshSendFacility &sendFacility) + : m_sendFacility(sendFacility), + m_bindAddress(bindAddress), + m_bindPort(bindPort), + m_state(SshTcpIpForwardServer::Inactive) +{ +} + +} // namespace Internal + +using namespace Internal; + +SshTcpIpForwardServer::SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort, + SshSendFacility &sendFacility) + : d(new SshTcpIpForwardServerPrivate(bindAddress, bindPort, sendFacility)) +{ + connect(&d->m_timeoutTimer, &QTimer::timeout, this, &SshTcpIpForwardServer::setClosed); +} + +void SshTcpIpForwardServer::setListening(quint16 port) +{ + QSSH_ASSERT_AND_RETURN(d->m_state != Listening); + d->m_bindPort = port; + d->m_state = Listening; + emit stateChanged(Listening); +} + +void SshTcpIpForwardServer::setClosed() +{ + QSSH_ASSERT_AND_RETURN(d->m_state != Inactive); + d->m_state = Inactive; + emit stateChanged(Inactive); +} + +void SshTcpIpForwardServer::setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection) +{ + d->m_pendingConnections.append(connection); + emit newConnection(); +} + +SshTcpIpForwardServer::~SshTcpIpForwardServer() +{ + delete d; +} + +void SshTcpIpForwardServer::initialize() +{ + if (d->m_state == Inactive || d->m_state == Closing) { + try { + d->m_state = Initializing; + emit stateChanged(Initializing); + d->m_sendFacility.sendTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_bindPort); + d->m_timeoutTimer.start(d->ReplyTimeout); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + d->m_timeoutTimer.stop(); + setClosed(); + } + } +} + +void SshTcpIpForwardServer::close() +{ + d->m_timeoutTimer.stop(); + + if (d->m_state == Initializing || d->m_state == Listening) { + try { + d->m_state = Closing; + emit stateChanged(Closing); + d->m_sendFacility.sendCancelTcpIpForwardPacket(d->m_bindAddress.toUtf8(), + d->m_bindPort); + d->m_timeoutTimer.start(d->ReplyTimeout); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + d->m_timeoutTimer.stop(); + setClosed(); + } + } +} + +const QString &SshTcpIpForwardServer::bindAddress() const +{ + return d->m_bindAddress; +} + +quint16 SshTcpIpForwardServer::port() const +{ + return d->m_bindPort; +} + +SshTcpIpForwardServer::State SshTcpIpForwardServer::state() const +{ + return d->m_state; +} + +SshForwardedTcpIpTunnel::Ptr SshTcpIpForwardServer::nextPendingConnection() +{ + return d->m_pendingConnections.takeFirst(); +} + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.h b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.h new file mode 100644 index 00000000..2a0ed7e3 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "ssh_global.h" +#include "sshforwardedtcpiptunnel.h" +#include + +namespace QSsh { + +namespace Internal { +class SshChannelManager; +class SshTcpIpForwardServerPrivate; +class SshSendFacility; +class SshConnectionPrivate; +} // namespace Internal + +class QSSH_EXPORT SshTcpIpForwardServer : public QObject +{ + Q_OBJECT + friend class Internal::SshChannelManager; + friend class Internal::SshConnectionPrivate; + +public: + enum State { + Inactive, + Initializing, + Listening, + Closing + }; + + typedef QSharedPointer Ptr; + ~SshTcpIpForwardServer(); + + const QString &bindAddress() const; + quint16 port() const; + State state() const; + void initialize(); + void close(); + + SshForwardedTcpIpTunnel::Ptr nextPendingConnection(); + +signals: + void error(const QString &reason); + void newConnection(); + void stateChanged(State state); + +private: + SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort, + Internal::SshSendFacility &sendFacility); + void setListening(quint16 port); + void setClosed(); + void setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection); + + Internal::SshTcpIpForwardServerPrivate * const d; +}; + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver_p.h b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver_p.h new file mode 100644 index 00000000..9f4775be --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshtcpipforwardserver_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshtcpipforwardserver.h" +#include +#include + +namespace QSsh { +namespace Internal { + +class SshTcpIpForwardServerPrivate +{ +public: + static const int ReplyTimeout = 10000; // milli seconds + + SshTcpIpForwardServerPrivate(const QString &bindAddress, quint16 bindPort, + SshSendFacility &sendFacility); + + SshSendFacility &m_sendFacility; + QTimer m_timeoutTimer; + + const QString m_bindAddress; + quint16 m_bindPort; + SshTcpIpForwardServer::State m_state; + + QList m_pendingConnections; +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshtcpiptunnel.cpp b/client/3rd/QtSsh/src/ssh/sshtcpiptunnel.cpp new file mode 100644 index 00000000..ac7bf520 --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshtcpiptunnel.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "sshsendfacility_p.h" +#include "sshtcpiptunnel_p.h" + +#include "sshincomingpacket_p.h" +#include "sshexception_p.h" +#include "sshlogging_p.h" + +namespace QSsh { + +namespace Internal { +SshTcpIpTunnelPrivate::SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility) + : AbstractSshChannel(channelId, sendFacility) +{ + connect(this, &AbstractSshChannel::eof, this, &SshTcpIpTunnelPrivate::handleEof); +} + +SshTcpIpTunnelPrivate::~SshTcpIpTunnelPrivate() +{ + closeChannel(); +} + + + +void SshTcpIpTunnelPrivate::handleChannelSuccess() +{ + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_SUCCESS message."); +} + +void SshTcpIpTunnelPrivate::handleChannelFailure() +{ + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_FAILURE message."); +} + +void SshTcpIpTunnelPrivate::handleOpenFailureInternal(const QString &reason) +{ + emit error(reason); + closeChannel(); +} + +void SshTcpIpTunnelPrivate::handleChannelDataInternal(const QByteArray &data) +{ + m_data += data; + emit readyRead(); +} + +void SshTcpIpTunnelPrivate::handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data) +{ + qCWarning(sshLog, "%s: Unexpected extended channel data. Type is %u, content is '%s'.", + Q_FUNC_INFO, type, data.constData()); +} + +void SshTcpIpTunnelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) +{ + qCWarning(sshLog, "%s: Unexpected exit status %d.", Q_FUNC_INFO, exitStatus.exitStatus); +} + +void SshTcpIpTunnelPrivate::handleExitSignal(const SshChannelExitSignal &signal) +{ + qCWarning(sshLog, "%s: Unexpected exit signal %s.", Q_FUNC_INFO, signal.signal.constData()); +} + +void SshTcpIpTunnelPrivate::closeHook() +{ + emit closed(); +} + +void SshTcpIpTunnelPrivate::handleEof() +{ + /* + * For some reason, the OpenSSH server only sends EOF when the remote port goes away, + * but does not close the channel, even though it becomes useless in that case. + * So we close it ourselves. + */ + closeChannel(); +} + +qint64 SshTcpIpTunnelPrivate::readData(char *data, qint64 maxlen) +{ + const qint64 bytesRead = qMin(qint64(m_data.count()), maxlen); + memcpy(data, m_data.constData(), bytesRead); + m_data.remove(0, bytesRead); + return bytesRead; +} + +qint64 SshTcpIpTunnelPrivate::writeData(const char *data, qint64 len) +{ + QSSH_ASSERT_AND_RETURN_VALUE(channelState() == AbstractSshChannel::SessionEstablished, 0); + + sendData(QByteArray(data, len)); + return len; +} + +} // namespace Internal + +} // namespace QSsh diff --git a/client/3rd/QtSsh/src/ssh/sshtcpiptunnel_p.h b/client/3rd/QtSsh/src/ssh/sshtcpiptunnel_p.h new file mode 100644 index 00000000..a9f2844c --- /dev/null +++ b/client/3rd/QtSsh/src/ssh/sshtcpiptunnel_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "sshchannel_p.h" +#include +#include + +namespace QSsh { +namespace Internal { + +class SshTcpIpTunnelPrivate : public AbstractSshChannel +{ + Q_OBJECT + +public: + SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility); + ~SshTcpIpTunnelPrivate(); + + template + void init(SshTcpIpTunnel *q) + { + connect(this, &SshTcpIpTunnelPrivate::closed, + q, &SshTcpIpTunnel::close, Qt::QueuedConnection); + connect(this, &SshTcpIpTunnelPrivate::readyRead, + q, &SshTcpIpTunnel::readyRead, Qt::QueuedConnection); + connect(this, &SshTcpIpTunnelPrivate::error, q, [q](const QString &reason) { + q->setErrorString(reason); + emit q->error(reason); + }, Qt::QueuedConnection); + } + + void handleChannelSuccess() override; + void handleChannelFailure() override; + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + +signals: + void readyRead(); + void error(const QString &reason); + void closed(); + +protected: + void handleOpenFailureInternal(const QString &reason) override; + void handleChannelDataInternal(const QByteArray &data) override; + void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data) override; + void handleExitStatus(const SshChannelExitStatus &exitStatus) override; + void handleExitSignal(const SshChannelExitSignal &signal) override; + void closeHook() override; + + QByteArray m_data; + +private: + void handleEof(); +}; + +} // namespace Internal +} // namespace QSsh diff --git a/client/3rd/QtSsh/sync.profile b/client/3rd/QtSsh/sync.profile new file mode 100644 index 00000000..92bb1d89 --- /dev/null +++ b/client/3rd/QtSsh/sync.profile @@ -0,0 +1,7 @@ +%modules = ( + "QtSsh" => "$basedir/src/ssh", +); + +%dependencies = ( + "qtbase" => "", +); diff --git a/client/3rd/QtSsh/tests/auto/auto.pro b/client/3rd/QtSsh/tests/auto/auto.pro new file mode 100644 index 00000000..8cded039 --- /dev/null +++ b/client/3rd/QtSsh/tests/auto/auto.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = +CONFIG-=create_cmake \ No newline at end of file diff --git a/client/3rd/QtSsh/tests/auto/cmake/cmake.pro b/client/3rd/QtSsh/tests/auto/cmake/cmake.pro new file mode 100644 index 00000000..da13e218 --- /dev/null +++ b/client/3rd/QtSsh/tests/auto/cmake/cmake.pro @@ -0,0 +1,3 @@ +# let cmake do nothing +TEMPLATE = subdirs +SUBDIRS = \ No newline at end of file diff --git a/client/3rd/QtSsh/tests/tests.pro b/client/3rd/QtSsh/tests/tests.pro new file mode 100644 index 00000000..85e4f3a5 --- /dev/null +++ b/client/3rd/QtSsh/tests/tests.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += auto diff --git a/client/client.pro b/client/client.pro new file mode 100644 index 00000000..9f2ac434 --- /dev/null +++ b/client/client.pro @@ -0,0 +1,102 @@ +QT += widgets core gui network xml + +TARGET = AmneziaVPN +TEMPLATE = app +CONFIG += console + +DEFINES += QT_DEPRECATED_WARNINGS + +include("3rd/QtSsh/src/ssh/ssh.pri") +include("3rd/QtSsh/src/botan/botan.pri") + +HEADERS += \ + communicator.h \ + core/defs.h \ + core/errorstrings.h \ + core/openvpnconfigurator.h \ + core/router.h \ + core/servercontroller.h \ + debug.h \ + defines.h \ + localclient.h \ + managementserver.h \ + message.h \ + runguard.h \ + settings.h \ + ui/Controls/SlidingStackedWidget.h \ + ui/mainwindow.h \ + utils.h \ + vpnconnection.h \ + protocols/vpnprotocol.h \ + protocols/openvpnprotocol.h \ + +SOURCES += \ + communicator.cpp \ + core/openvpnconfigurator.cpp \ + core/router.cpp \ + core/servercontroller.cpp \ + debug.cpp \ + localclient.cpp \ + main.cpp \ + managementserver.cpp \ + message.cpp \ + runguard.cpp \ + settings.cpp \ + ui/Controls/SlidingStackedWidget.cpp \ + ui/mainwindow.cpp \ + utils.cpp \ + vpnconnection.cpp \ + protocols/vpnprotocol.cpp \ + protocols/openvpnprotocol.cpp \ + +FORMS += ui/mainwindow.ui + +RESOURCES += \ + resources.qrc + +TRANSLATIONS = \ + translations/amneziavpn_ru.ts + +CONFIG(release, debug|release) { + DESTDIR = $$PWD/../../AmneziaVPN-build/client/release + MOC_DIR = $$DESTDIR + OBJECTS_DIR = $$DESTDIR + RCC_DIR = $$DESTDIR +} + +win32 { + OTHER_FILES += platform_win/vpnclient.rc + RC_FILE = platform_win/vpnclient.rc + + HEADERS += \ + ui/framelesswindow.h \ + + SOURCES += \ + ui/framelesswindow.cpp + + VERSION = 1.0.0.0 + QMAKE_TARGET_COMPANY = "AmneziaVPN" + QMAKE_TARGET_PRODUCT = "AmneziaVPN" + + + + LIBS += \ + -luser32 \ + -lrasapi32 \ + -lshlwapi \ + -liphlpapi \ + -lws2_32 \ + -liphlpapi \ + -lgdi32 + + #LIBS += -L$$PWD/../../../../../../../OpenSSL-Win32/lib/ -llibcrypto +} + +macx { + ICON = $$PWD/images/app.icns + + HEADERS += ui/macos_util.h + SOURCES += ui/macos_util.mm + + LIBS += -framework Cocoa +} diff --git a/client/communicator.cpp b/client/communicator.cpp new file mode 100644 index 00000000..0dd3ca3c --- /dev/null +++ b/client/communicator.cpp @@ -0,0 +1,76 @@ +#include "communicator.h" +#include "defines.h" +#include "localclient.h" +#include "utils.h" + +Communicator::Communicator(QObject* parent) : QObject(parent), + m_localClient(nullptr) +{ + connectToServer(); +} + +Communicator::~Communicator() +{ + +} + +void Communicator::connectToServer() +{ + if (m_localClient) { + delete m_localClient; + } + + m_localClient = new LocalClient(this); + connect(m_localClient, &LocalClient::connected, this, &Communicator::onConnected); + connect(m_localClient, &LocalClient::lineAvailable, this, &Communicator::onLineAvailable); + + m_localClient->connectToServer(Utils::serverName()); +} + +void Communicator::onConnected() +{ + qDebug().noquote() << QString("Connected to local server '%1'").arg(m_localClient->serverName()); + Message message(Message::State::Initialize, QStringList({"Client"})); + sendMessage(message); +} + +void Communicator::onLineAvailable(const QString& line) +{ + Message message(line); + if (!message.isValid()) { + qDebug() << "Message is not valid"; + return; + } + + emit messageReceived(message); +} + +bool Communicator::connected() const +{ + if (!m_localClient) { + return false; + } + + return m_localClient->connectedState(); +} + +QString Communicator::readData() +{ + return QString(); +} + +bool Communicator::writeData(const QString& data) +{ + return m_localClient->write(data.toUtf8()); +} + +void Communicator::sendMessage(const Message& message) +{ + if (!connected()) { + return; + } + const QString data = message.toString(); + bool status = writeData(data + "\n"); + + qDebug().noquote() << QString("Send message '%1', status '%2'").arg(data).arg(Utils::toString(status)); +} diff --git a/client/communicator.h b/client/communicator.h new file mode 100644 index 00000000..8546bd59 --- /dev/null +++ b/client/communicator.h @@ -0,0 +1,41 @@ +#ifndef COMMUNICATOR_H +#define COMMUNICATOR_H + +#include +#include + +#include "message.h" + +class LocalClient; + +class Communicator : public QObject +{ + Q_OBJECT + +public: + explicit Communicator(QObject* parent = nullptr); + ~Communicator(); + + bool connected() const; + void sendMessage(const Message& message); + +signals: + void messageReceived(const Message& message); + + void comminicatorConnected(); + void comminicatorDisconnected(); + +protected slots: + void onConnected(); + void onLineAvailable(const QString& line); + +protected: + QString readData(); + bool writeData(const QString& data); + void connectToServer(); + + LocalClient* m_localClient; +}; + + +#endif // COMMUNICATOR_H diff --git a/client/core/defs.h b/client/core/defs.h new file mode 100644 index 00000000..230a4457 --- /dev/null +++ b/client/core/defs.h @@ -0,0 +1,56 @@ +#ifndef DEFS_H +#define DEFS_H + +#include + +namespace amnezia { + +enum class Protocol { + Any, + OpenVpn, + ShadowSocks, + WireGuard +}; + +struct ServerCredentials +{ + QString hostName; + QString userName; + QString password; + int port = 22; +}; + +enum ErrorCode +{ + // General error codes + NoError = 0, + UnknownError, + InternalError, + NotImplementedError, + + // Server errorz + ServerCheckFailed, + + // Ssh connection errors + SshSocketError, SshTimeoutError, SshProtocolError, + SshHostKeyError, SshKeyFileError, SshAuthenticationError, + SshClosedByServerError, SshInternalError, + + // Ssh remote process errors + SshRemoteProcessCreationError, + FailedToStartRemoteProcessError, RemoteProcessCrashError, + + // Local errors + FailedToSaveConfigData, + OpenVpnConfigMissing, + OpenVpnManagementServerError, + + // Distro errors + AmneziaServiceConnectionFailed, + OpenVpnExecutableMissing, + EasyRsaExecutableMissing +}; + +} // namespace amnezia + +#endif // DEFS_H diff --git a/client/core/errorstrings.h b/client/core/errorstrings.h new file mode 100644 index 00000000..e3933ae6 --- /dev/null +++ b/client/core/errorstrings.h @@ -0,0 +1,47 @@ +#ifndef ERRORSTRINGS_H +#define ERRORSTRINGS_H + +#include "defs.h" +using namespace amnezia; + +QString errorString(ErrorCode code){ + switch (code) { + + // General error codes + case(NoError): return QObject::tr("No error"); + case(UnknownError): return QObject::tr("Unknown Error"); + case(NotImplementedError): return QObject::tr("Function not implemented"); + case(ServerCheckFailed): return QObject::tr("Server check failed"); + + // Ssh connection errors + case(SshSocketError): return QObject::tr("Ssh connection error"); + case(SshTimeoutError): return QObject::tr("Ssh connection timeout"); + case(SshProtocolError): return QObject::tr("Ssh protocol error"); + case(SshHostKeyError): return QObject::tr("Ssh server ket check failed"); + case(SshKeyFileError): return QObject::tr("Ssh key file error"); + case(SshAuthenticationError): return QObject::tr("Ssh authentication error"); + case(SshClosedByServerError): return QObject::tr("Ssh session closed"); + case(SshInternalError): return QObject::tr("Ssh internal error"); + + // Ssh remote process errors + case(SshRemoteProcessCreationError): return QObject::tr("Failed to create remote process on server"); + case(FailedToStartRemoteProcessError): return QObject::tr("Failed to start remote process on server"); + case(RemoteProcessCrashError): return QObject::tr("Remote process on server crashed"); + + // Local errors + case (FailedToSaveConfigData): return QObject::tr("Failed to save config to disk"); + case (OpenVpnConfigMissing): return QObject::tr("OpenVPN config missing"); + case (OpenVpnManagementServerError): return QObject::tr("OpenVpn management server error"); + + case (OpenVpnExecutableMissing): return QObject::tr("OpenVPN executable missing"); + case (EasyRsaExecutableMissing): return QObject::tr("EasyRsa executable missing"); + case (AmneziaServiceConnectionFailed): return QObject::tr("Amnezia helper service error"); + + case(InternalError): + default: + return QObject::tr("Internal error"); + } +} + + +#endif // ERRORSTRINGS_H diff --git a/client/core/openvpnconfigurator.cpp b/client/core/openvpnconfigurator.cpp new file mode 100644 index 00000000..72389761 --- /dev/null +++ b/client/core/openvpnconfigurator.cpp @@ -0,0 +1,167 @@ +#include "openvpnconfigurator.h" +#include +#include +#include +#include +#include +#include + +QString OpenVpnConfigurator::getRandomString(int len) +{ + const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + + QString randomString; + for(int i=0; igenerate() % possibleCharacters.length(); + QChar nextChar = possibleCharacters.at(index); + randomString.append(nextChar); + } + return randomString; +} + +QString OpenVpnConfigurator::getEasyRsaShPath() +{ + QString easyRsaShPath = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\easyrsa\\easyrsa"; + easyRsaShPath.replace(":", ""); + easyRsaShPath.replace("\\", "/"); + easyRsaShPath.prepend("/"); + + return easyRsaShPath; +} + +QProcessEnvironment OpenVpnConfigurator::prepareEnv() +{ + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString pathEnvVar = env.value("PATH"); + pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\easyrsa\\bin;"); + + env.insert("PATH", pathEnvVar); + return env; +} + +void OpenVpnConfigurator::initPKI(const QString &path) +{ +#ifdef Q_OS_WIN + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + p.setProcessEnvironment(prepareEnv()); + + QString command = QString("sh.exe"); + + p.setNativeArguments(getEasyRsaShPath() + " init-pki"); + + p.setWorkingDirectory(path); + + p.start(command); + p.waitForFinished(); + qDebug().noquote() << p.readAll(); + +#endif +} + +QString OpenVpnConfigurator::genReq(const QString &path, const QString &clientId) +{ +#ifdef Q_OS_WIN + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + p.setProcessEnvironment(prepareEnv()); + + QString command = QString("sh.exe"); + + p.setNativeArguments(getEasyRsaShPath() + " gen-req " + clientId + " nopass"); + + p.setWorkingDirectory(path); + + QObject::connect(&p, &QProcess::channelReadyRead, [&](){ + QString data = p.readAll(); + qDebug().noquote() << data; + + if (data.contains("Common Name (eg: your user, host, or server name)")) { + p.write("\n"); + } + }); + + p.start(command); + p.waitForFinished(); +// qDebug().noquote() << p.readAll(); + + return ""; +#endif +} + + +OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest() +{ + OpenVpnConfigurator::ConnectionData connData; + connData.clientId = getRandomString(32); + + QTemporaryDir dir; +// if (dir.isValid()) { +// // dir.path() returns the unique directory path +// } + + QString path = dir.path(); + + initPKI(path); + genReq(path, connData.clientId); + + + QFile req(path + "/pki/reqs/" + connData.clientId + ".req"); + req.open(QIODevice::ReadOnly); + connData.request = req.readAll(); + + QFile key(path + "/pki/private/" + connData.clientId + ".key"); + key.open(QIODevice::ReadOnly); + connData.privKey = key.readAll(); + + qDebug().noquote() << connData.request; + qDebug().noquote() << connData.privKey; + + + return connData; +} + +OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode) +{ + OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest(); + connData.host = credentials.hostName; + + QString reqFileName = QString("/opt/amneziavpn_data/clients/%1.req").arg(connData.clientId); + ErrorCode e = ServerController::uploadTextFileToContainer(credentials, connData.request, reqFileName); + if (e) { + *errorCode = e; + return connData; + } + + ServerController::signCert(credentials, connData.clientId); + + connData.caCert = ServerController::getTextFileFromContainer(credentials, ServerController::caCertPath(), &e); + connData.clientCert = ServerController::getTextFileFromContainer(credentials, ServerController::clientCertPath() + QString("%1.crt").arg(connData.clientId), &e); + if (e) { + *errorCode = e; + return connData; + } + + connData.taKey = ServerController::getTextFileFromContainer(credentials, ServerController::taKeyPath(), &e); + + return connData; +} + +QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode) +{ + QFile configTemplFile(":/server_scripts/template.ovpn"); + configTemplFile.open(QIODevice::ReadOnly); + QString config = configTemplFile.readAll(); + + ConnectionData connData = prepareOpenVpnConfig(credentials, errorCode); + + config.replace("$PROTO", "udp"); + config.replace("$REMOTE_HOST", connData.host); + config.replace("$REMOTE_PORT", "1194"); + config.replace("$CA_CERT", connData.caCert); + config.replace("$CLIENT_CERT", connData.clientCert); + config.replace("$PRIV_KEY", connData.privKey); + config.replace("$TA_KEY", connData.taKey); + + return config; +} diff --git a/client/core/openvpnconfigurator.h b/client/core/openvpnconfigurator.h new file mode 100644 index 00000000..a4e965d4 --- /dev/null +++ b/client/core/openvpnconfigurator.h @@ -0,0 +1,41 @@ +#ifndef OPENVPNCONFIGURATOR_H +#define OPENVPNCONFIGURATOR_H + +#include +#include + +#include "defs.h" +#include "servercontroller.h" + + +class OpenVpnConfigurator +{ +public: + + struct ConnectionData { + QString clientId; + QString request; // certificate request + QString privKey; // client private key + QString clientCert; // client signed certificate + QString caCert; // server certificate + QString taKey; // tls-auth key + QString host; // host ip + }; + + static QString genOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); + +private: + static QString getRandomString(int len); + static QString getEasyRsaShPath(); + + static QProcessEnvironment prepareEnv(); + static void initPKI(const QString &path); + static QString genReq(const QString &path, const QString &clientId); + + static ConnectionData createCertRequest(); + + static ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); + +}; + +#endif // OPENVPNCONFIGURATOR_H diff --git a/client/core/router.cpp b/client/core/router.cpp new file mode 100644 index 00000000..0c230879 --- /dev/null +++ b/client/core/router.cpp @@ -0,0 +1,317 @@ +#include "router.h" + +#include + + +Router &Router::Instance() +{ + static Router s; + return s; +} + +bool Router::routeAdd(const QString &ip, const QString &gw, QString mask) +{ +#ifdef Q_OS_WIN + + qDebug().noquote() << QString("ROUTE ADD: IP:%1 %2 GW %3") + .arg(ip) + .arg(mask) + .arg(gw); + + if (mask == "") { + mask = "255.255.255.255"; + if (ip.endsWith(".0")) mask = "255.255.255.0"; + if (ip.endsWith(".0.0")) mask = "255.255.0.0"; + if (ip.endsWith(".0.0.0")) mask = "255.0.0.0"; + } + + + PMIB_IPFORWARDTABLE pIpForwardTable = NULL; + MIB_IPFORWARDROW ipfrow; + DWORD dwSize = 0; + BOOL bOrder = FALSE; + DWORD dwStatus = 0; + + + // Find out how big our buffer needs to be. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + if (dwStatus == ERROR_INSUFFICIENT_BUFFER) { + // Allocate the memory for the table + if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) { + qDebug() << "Malloc failed. Out of memory."; + return false; + } + // Now get the table. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + } + + + if (dwStatus != ERROR_SUCCESS) { + qDebug() << "getIpForwardTable failed."; + if (pIpForwardTable) + free(pIpForwardTable); + return false; + } + + // Set iface for route + IPAddr dwGwAddr = inet_addr(gw.toStdString().c_str()); + if (GetBestInterface(dwGwAddr, &ipfrow.dwForwardIfIndex) != NO_ERROR) { + qDebug() << "Router::routeAdd : GetBestInterface failed"; + return false; + } + + // address + ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str()); + + // mask + in_addr maskAddr; + inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr); + ipfrow.dwForwardMask = maskAddr.S_un.S_addr; + + // Get TAP iface metric to set it for new routes + MIB_IPINTERFACE_ROW tap_iface; + InitializeIpInterfaceEntry(&tap_iface); + tap_iface.InterfaceIndex = ipfrow.dwForwardIfIndex; + tap_iface.Family = AF_INET; + dwStatus = GetIpInterfaceEntry(&tap_iface); + if (dwStatus == NO_ERROR){ + ipfrow.dwForwardMetric1 = tap_iface.Metric; + } + else { + qDebug() << "Router::routeAdd: failed GetIpInterfaceEntry(), Error:" << dwStatus; + ipfrow.dwForwardMetric1 = 256; + } + ipfrow.dwForwardMetric2 = 0; + ipfrow.dwForwardMetric3 = 0; + ipfrow.dwForwardMetric4 = 0; + ipfrow.dwForwardMetric5 = 0; + + ipfrow.dwForwardAge = 0; + + ipfrow.dwForwardNextHop = inet_addr(gw.toStdString().c_str()); + ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */ + ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */ + + + dwStatus = CreateIpForwardEntry(&ipfrow); + if (dwStatus == NO_ERROR){ + ipForwardRows.append(ipfrow); + //qDebug() << "Gateway changed successfully"; + } + else { + qDebug() << "Router::routeAdd: failed CreateIpForwardEntry()"; + qDebug() << "Error: " << dwStatus; + } + + // Free resources + if (pIpForwardTable) + free(pIpForwardTable); + + return (dwStatus == NO_ERROR); + +#endif +} + +int Router::routeAddList(const QString &gw, const QStringList &ips) +{ + qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2") + .arg(ips.size()) + .arg(gw); + + qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1") + .arg(ips.join("\n")); + +#ifdef Q_OS_WIN + + PMIB_IPFORWARDTABLE pIpForwardTable = NULL; + DWORD dwSize = 0; + BOOL bOrder = FALSE; + DWORD dwStatus = 0; + + + // Find out how big our buffer needs to be. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + if (dwStatus == ERROR_INSUFFICIENT_BUFFER) { + // Allocate the memory for the table + if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) { + qDebug() << "Malloc failed. Out of memory."; + return 0; + } + // Now get the table. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + } + + + if (dwStatus != ERROR_SUCCESS) { + qDebug() << "getIpForwardTable failed."; + if (pIpForwardTable) + free(pIpForwardTable); + return 0; + } + + + int success_count = 0; + + + + QString mask; + + MIB_IPFORWARDROW ipfrow; + + + ipfrow.dwForwardPolicy = 0; + ipfrow.dwForwardAge = 0; + + ipfrow.dwForwardNextHop = inet_addr(gw.toStdString().c_str()); + ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */ + ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */ + + + // Set iface for route + IPAddr dwGwAddr = inet_addr(gw.toStdString().c_str()); + if (GetBestInterface(dwGwAddr, &ipfrow.dwForwardIfIndex) != NO_ERROR) { + qDebug() << "Router::routeAddList : GetBestInterface failed"; + return false; + } + + // Get TAP iface metric to set it for new routes + MIB_IPINTERFACE_ROW tap_iface; + InitializeIpInterfaceEntry(&tap_iface); + tap_iface.InterfaceIndex = ipfrow.dwForwardIfIndex; + tap_iface.Family = AF_INET; + dwStatus = GetIpInterfaceEntry(&tap_iface); + if (dwStatus == NO_ERROR){ + ipfrow.dwForwardMetric1 = tap_iface.Metric; + } + else { + qDebug() << "Router::routeAddList: failed GetIpInterfaceEntry(), Error:" << dwStatus; + ipfrow.dwForwardMetric1 = 256; + } + ipfrow.dwForwardMetric2 = 0; + ipfrow.dwForwardMetric3 = 0; + ipfrow.dwForwardMetric4 = 0; + ipfrow.dwForwardMetric5 = 0; + + for (int i = 0; i < ips.size(); ++i) { + QString ip = ips.at(i); + if (ip.isEmpty()) continue; + + mask = "255.255.255.255"; + if (ip.endsWith(".0")) mask = "255.255.255.0"; + if (ip.endsWith(".0.0")) mask = "255.255.0.0"; + if (ip.endsWith(".0.0.0")) mask = "255.0.0.0"; + + // address + ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str()); + + + // mask + in_addr maskAddr; + inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr); + ipfrow.dwForwardMask = maskAddr.S_un.S_addr; + + dwStatus = CreateIpForwardEntry(&ipfrow); + if (dwStatus == NO_ERROR){ + ipForwardRows.append(ipfrow); + //qDebug() << "Gateway changed successfully"; + } + else { + qDebug() << "Router::routeAdd: failed CreateIpForwardEntry(), Error:" << ip << dwStatus; + } + + if (dwStatus == NO_ERROR) success_count++; + } + + + // Free resources + if (pIpForwardTable) + free(pIpForwardTable); + + qDebug() << "Router::routeAddList finished, success: " << success_count << "/" << ips.size(); + return success_count; + +#endif +} + +bool Router::clearSavedRoutes() +{ +#ifdef Q_OS_WIN + + if (ipForwardRows.isEmpty()) return true; + + qDebug() << "forward rows size:" << ipForwardRows.size(); + + // Declare and initialize variables + PMIB_IPFORWARDTABLE pIpForwardTable = NULL; + DWORD dwSize = 0; + BOOL bOrder = FALSE; + DWORD dwStatus = 0; + + // Find out how big our buffer needs to be. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + if (dwStatus == ERROR_INSUFFICIENT_BUFFER) { + // Allocate the memory for the table + if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) { + qDebug() << "Router::clearSavedRoutes : Malloc failed. Out of memory"; + return false; + } + // Now get the table. + dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder); + } + + if (dwStatus != ERROR_SUCCESS) { + qDebug() << "Router::clearSavedRoutes : getIpForwardTable failed"; + if (pIpForwardTable) + free(pIpForwardTable); + return false; + } + + int removed_count = 0; + for (int i = 0; i < ipForwardRows.size(); ++i) { + dwStatus = DeleteIpForwardEntry(&ipForwardRows[i]); + + if (dwStatus != ERROR_SUCCESS) { + qDebug() << "Router::clearSavedRoutes : Could not delete old row" << i; + } + else removed_count++; + } + + if (pIpForwardTable) + free(pIpForwardTable); + + qDebug() << "Router::clearSavedRoutes : removed routes:" << removed_count << "of" << ipForwardRows.size(); + ipForwardRows.clear(); + + return true; + +#endif +} + +bool Router::routeDelete(const QString &ip) +{ +#ifdef Q_OS_WIN + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + QString command = QString("route delete %1") + .arg(ip); + + p.start(command); + p.waitForFinished(); + qDebug().noquote() << "OUTPUT route delete: " + p.readAll(); + + return true; +#endif +} + +void Router::flushDns() +{ +#ifdef Q_OS_WIN + QProcess p; + p.setProcessChannelMode(QProcess::MergedChannels); + QString command = QString("ipconfig /flushdns"); + + p.start(command); + p.waitForFinished(); + qDebug().noquote() << "OUTPUT ipconfig /flushdns: " + p.readAll(); +#endif +} diff --git a/client/core/router.h b/client/core/router.h new file mode 100644 index 00000000..655bf90b --- /dev/null +++ b/client/core/router.h @@ -0,0 +1,60 @@ +#ifndef ROUTER_H +#define ROUTER_H + +#include +#include +#include +#include +#include + + +#ifdef Q_OS_WIN +#include //includes Windows.h +#include + + +#include +#include +#include +#include + + +#include +typedef uint8_t u8_t ; + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + + +#endif //Q_OS_WIN + + +/** + * @brief The Router class - General class for handling ip routing + */ +class Router : public QObject +{ + Q_OBJECT +public: + static Router& Instance(); + + bool routeAdd(const QString &ip, const QString &gw, QString mask = QString()); + int routeAddList(const QString &gw, const QStringList &ips); + bool clearSavedRoutes(); + bool routeDelete(const QString &ip); + void flushDns(); + +public slots: + +private: + Router() {} + Router(Router const &) = delete; + Router& operator= (Router const&) = delete; + +#ifdef Q_OS_WIN + QList ipForwardRows; +#endif +}; + +#endif // ROUTER_H diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp new file mode 100644 index 00000000..78828597 --- /dev/null +++ b/client/core/servercontroller.cpp @@ -0,0 +1,347 @@ +#include "servercontroller.h" + +#include +#include +#include +#include +#include + +#include "sshconnectionmanager.h" + + +using namespace QSsh; + +ErrorCode ServerController::runScript(const SshConnectionParameters &sshParams, QString script) +{ + QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); + + SshConnection *client = connectToHost(sshParams); + if (client->state() != SshConnection::State::Connected) { + return fromSshConnectionErrorCode(client->errorState()); + } + + script.replace("\r", ""); + + qDebug() << "Run script"; + + const QStringList &lines = script.split("\n", QString::SkipEmptyParts); + for (int i = 0; i < lines.count(); i++) { + const QString &line = lines.at(i); + if (line.startsWith("#")) { + continue; + } + + qDebug().noquote() << "EXEC" << line; + QSharedPointer proc = client->createRemoteProcess(line.toUtf8()); + + if (!proc) { + qCritical() << "Failed to create SshRemoteProcess, breaking."; + return ErrorCode::SshRemoteProcessCreationError; + } + + QEventLoop wait; + int exitStatus; + +// QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){ +// qDebug() << "Command started"; +// }); + + QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){ + exitStatus = status; + //qDebug() << "Remote process exited with status" << status; + wait.quit(); + }); + +// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){ +// QString s = proc->readAllStandardOutput(); +// if (s != "." && !s.isEmpty()) { +// qDebug().noquote() << s << s.size(); +// } +// }); + +// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){ +// QString s = proc->readAllStandardError(); +// if (s != "." && !s.isEmpty()) { +// qDebug().noquote() << s; +// } +// }); + + proc->start(); + + if (i < lines.count() - 1) { + wait.exec(); + } + + if (SshRemoteProcess::ExitStatus(exitStatus) != QSsh::SshRemoteProcess::ExitStatus::NormalExit) { + return fromSshProcessExitStatus(exitStatus); + } + } + + qDebug() << "ServerController::runScript finished\n"; + return ErrorCode::NoError; +} + +ErrorCode ServerController::uploadTextFileToContainer(const ServerCredentials &credentials, + QString &file, const QString &path) +{ + QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); + + QString script = QString("docker exec -i amneziavpn sh -c \"echo \'%1\' > %2\""). + arg(file).arg(path); + + qDebug().noquote() << script; + + SshConnection *client = connectToHost(sshParams(credentials)); + if (client->state() != SshConnection::State::Connected) { + return fromSshConnectionErrorCode(client->errorState()); + } + + QSharedPointer proc = client->createRemoteProcess(script.toUtf8()); + + if (!proc) { + qCritical() << "Failed to create SshRemoteProcess, breaking."; + return ErrorCode::SshRemoteProcessCreationError; + } + + QEventLoop wait; + int exitStatus = 0; + +// QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){ +// qDebug() << "Command started"; +// }); + + QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){ + //qDebug() << "Remote process exited with status" << status; + exitStatus = status; + wait.quit(); + }); + +// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){ +// qDebug().noquote() << proc->readAllStandardOutput(); +// }); + +// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){ +// qDebug().noquote() << proc->readAllStandardError(); +// }); + + proc->start(); + wait.exec(); + + return fromSshProcessExitStatus(exitStatus); +} + +QString ServerController::getTextFileFromContainer(const ServerCredentials &credentials, const QString &path, + ErrorCode *errorCode) +{ + QString script = QString("docker exec -i amneziavpn sh -c \"cat \'%1\'\""). + arg(path); + + qDebug().noquote() << "Copy file from container\n" << script; + + SshConnection *client = connectToHost(sshParams(credentials)); + if (client->state() != SshConnection::State::Connected) { + if (errorCode) *errorCode = fromSshConnectionErrorCode(client->errorState()); + return QString(); + } + + QSharedPointer proc = client->createRemoteProcess(script.toUtf8()); + if (!proc) { + qCritical() << "Failed to create SshRemoteProcess, breaking."; + if (errorCode) *errorCode = ErrorCode::SshRemoteProcessCreationError; + return QString(); + } + + QEventLoop wait; + int exitStatus = 0; + + QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){ + exitStatus = status; + wait.quit(); + }); + + proc->start(); + wait.exec(); + + if (SshRemoteProcess::ExitStatus(exitStatus) != QSsh::SshRemoteProcess::ExitStatus::NormalExit) { + if (errorCode) *errorCode = fromSshProcessExitStatus(exitStatus); + } + + return proc->readAllStandardOutput(); +} + +ErrorCode ServerController::signCert(const ServerCredentials &credentials, QString clientId) +{ + QString script_import = QString("docker exec -i amneziavpn bash -c \"cd /opt/amneziavpn_data && " + "easyrsa import-req /opt/amneziavpn_data/clients/%1.req %1 &>/dev/null\"") + .arg(clientId); + + QString script_sign = QString("docker exec -i amneziavpn bash -c \"export EASYRSA_BATCH=1; cd /opt/amneziavpn_data && " + "easyrsa sign-req client %1 &>/dev/null\"") + .arg(clientId); + + QStringList script {script_import, script_sign}; + + return runScript(sshParams(credentials), script.join("\n")); +} + +ErrorCode ServerController::checkOpenVpnServer(const ServerCredentials &credentials) +{ + QString caCert = ServerController::getTextFileFromContainer(credentials, ServerController::caCertPath()); + QString taKey = ServerController::getTextFileFromContainer(credentials, ServerController::taKeyPath()); + + if (!caCert.isEmpty() && !taKey.isEmpty()) { + return ErrorCode::NoError; + } + else { + return ErrorCode::ServerCheckFailed; + } +} + +ErrorCode ServerController::fromSshConnectionErrorCode(SshError error) +{ + switch (error) { + case(SshNoError): return ErrorCode::NoError; + case(QSsh::SshSocketError): return ErrorCode::SshSocketError; + case(QSsh::SshTimeoutError): return ErrorCode::SshTimeoutError; + case(QSsh::SshProtocolError): return ErrorCode::SshProtocolError; + case(QSsh::SshHostKeyError): return ErrorCode::SshHostKeyError; + case(QSsh::SshKeyFileError): return ErrorCode::SshKeyFileError; + case(QSsh::SshAuthenticationError): return ErrorCode::SshAuthenticationError; + case(QSsh::SshClosedByServerError): return ErrorCode::SshClosedByServerError; + case(QSsh::SshInternalError): return ErrorCode::SshInternalError; + } +} + +ErrorCode ServerController::fromSshProcessExitStatus(int exitStatus) +{ + switch (SshRemoteProcess::ExitStatus(exitStatus)) { + case(SshRemoteProcess::ExitStatus::NormalExit): return ErrorCode::NoError; + case(SshRemoteProcess::ExitStatus::FailedToStart): return ErrorCode::FailedToStartRemoteProcessError; + case(SshRemoteProcess::ExitStatus::CrashExit): return ErrorCode::RemoteProcessCrashError; + } +} + +SshConnectionParameters ServerController::sshParams(const ServerCredentials &credentials) +{ + QSsh::SshConnectionParameters sshParams; + sshParams.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword; + sshParams.host = credentials.hostName; + sshParams.userName = credentials.userName; + sshParams.password = credentials.password; + sshParams.timeout = 10; + sshParams.port = credentials.port; + sshParams.hostKeyCheckingMode = QSsh::SshHostKeyCheckingMode::SshHostKeyCheckingNone; + + return sshParams; +} + +ErrorCode ServerController::removeServer(const ServerCredentials &credentials, Protocol proto) +{ + QString scriptFileName; + + if (proto == Protocol::OpenVpn) { + scriptFileName = ":/server_scripts/remove_openvpn_server.sh"; + } + + QString scriptData; + + QFile file(scriptFileName); + if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError; + + scriptData = file.readAll(); + if (scriptData.isEmpty()) return ErrorCode::InternalError; + + return runScript(sshParams(credentials), scriptData); +} + +ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Protocol proto) +{ + if (proto == Protocol::OpenVpn) { + return setupOpenVpnServer(credentials); + } + else if (proto == Protocol::ShadowSocks) { + return setupShadowSocksServer(credentials); + } + else if (proto == Protocol::Any) { + // TODO: run concurently + return setupOpenVpnServer(credentials); + //setupShadowSocksServer(credentials); + } + + return ErrorCode::NotImplementedError; +} + +ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials) +{ + QString scriptData; + QString scriptFileName = ":/server_scripts/setup_openvpn_server.sh"; + QFile file(scriptFileName); + if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError; + + scriptData = file.readAll(); + if (scriptData.isEmpty()) return ErrorCode::InternalError; + + ErrorCode e = runScript(sshParams(credentials), scriptData); + if (e) return e; + + //return ok; + return checkOpenVpnServer(credentials); +} + +ErrorCode ServerController::setupShadowSocksServer(const ServerCredentials &credentials) +{ + return ErrorCode::NotImplementedError; +} + +SshConnection *ServerController::connectToHost(const SshConnectionParameters &sshParams) +{ + SshConnection *client = acquireConnection(sshParams); + + QEventLoop waitssh; + QObject::connect(client, &SshConnection::connected, &waitssh, [&]() { + qDebug() << "Server connected by ssh"; + waitssh.quit(); + }); + + QObject::connect(client, &SshConnection::disconnected, &waitssh, [&]() { + qDebug() << "Server disconnected by ssh"; + waitssh.quit(); + }); + + QObject::connect(client, &SshConnection::error, &waitssh, [&](QSsh::SshError error) { + qCritical() << "Ssh error:" << error << client->errorString(); + waitssh.quit(); + }); + + +// QObject::connect(client, &SshConnection::dataAvailable, [&](const QString &message) { +// qCritical() << "Ssh message:" << message; +// }); + + //qDebug() << "Connection state" << client->state(); + + if (client->state() == SshConnection::State::Unconnected) { + client->connectToHost(); + waitssh.exec(); + } + + +// QObject::connect(&client, &SshClient::sshDataReceived, [&](){ +// qDebug().noquote() << "Data received"; +// }); + + +// if(client.sshState() != SshClient::SshState::Ready) { +// qCritical() << "Can't connect to server"; +// return false; +// } +// else { +// qDebug() << "SSh connection established"; +// } + + +// QObject::connect(proc, &SshProcess::finished, &wait, &QEventLoop::quit); +// QObject::connect(proc, &SshProcess::failed, &wait, &QEventLoop::quit); + + return client; +} diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h new file mode 100644 index 00000000..f4458791 --- /dev/null +++ b/client/core/servercontroller.h @@ -0,0 +1,46 @@ +#ifndef SERVERCONTROLLER_H +#define SERVERCONTROLLER_H + +#include +#include "sshconnection.h" +#include "sshremoteprocess.h" +#include "defs.h" + +using namespace amnezia; + +class ServerController : public QObject +{ + Q_OBJECT +public: + + static ErrorCode fromSshConnectionErrorCode(QSsh::SshError error); + + // QSsh exitCode and exitStatus are different things + static ErrorCode fromSshProcessExitStatus(int exitStatus); + + static QString caCertPath() { return "/opt/amneziavpn_data/pki/ca.crt"; } + static QString clientCertPath() { return "/opt/amneziavpn_data/pki/issued/"; } + static QString taKeyPath() { return "/opt/amneziavpn_data/ta.key"; } + + static QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials); + + static ErrorCode removeServer(const ServerCredentials &credentials, Protocol proto); + static ErrorCode setupServer(const ServerCredentials &credentials, Protocol proto); + + static ErrorCode checkOpenVpnServer(const ServerCredentials &credentials); + + static ErrorCode uploadTextFileToContainer(const ServerCredentials &credentials, QString &file, const QString &path); + static QString getTextFileFromContainer(const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr); + + static ErrorCode signCert(const ServerCredentials &credentials, QString clientId); + +private: + static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); + static ErrorCode runScript(const QSsh::SshConnectionParameters &sshParams, QString script); + + static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials); + static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials); + +}; + +#endif // SERVERCONTROLLER_H diff --git a/client/debug.cpp b/client/debug.cpp new file mode 100644 index 00000000..a54b0131 --- /dev/null +++ b/client/debug.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#include + +#include "debug.h" +#include "defines.h" + +QFile Debug::m_file; +QTextStream Debug::m_textStream; +QString Debug::m_logFileName; + +void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + if (msg.simplified().isEmpty()) { + return; + } + + // Skip annoying messages from Qt + if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font")) { + return; + } + + Debug::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush; + + std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; +} + +bool Debug::init() +{ + QString path = userLogsDir(); + QDir appDir(path); + if (!appDir.mkpath(path)) { + return false; + } + + m_logFileName = QString("%1.log").arg(APPLICATION_NAME); + + qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}"); + + m_file.setFileName(appDir.filePath(m_logFileName)); + if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "Cannot open log file:" << m_logFileName; + return false; + } + m_file.setTextModeEnabled(true); + m_textStream.setDevice(&m_file); + qInstallMessageHandler(debugMessageHandler); + + return true; +} + +QString Debug::userLogsDir() +{ + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log"; +} + +bool Debug::openLogsFolder() +{ + QString path = userLogsDir(); +#ifdef Q_OS_WIN + path = "file:///" + path; +#endif + if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) { + qWarning() << "Can't open url:" << path; + return false; + } + return true; +} + +QString Debug::appLogFileNamePath() +{ + return m_file.fileName(); +} diff --git a/client/debug.h b/client/debug.h new file mode 100644 index 00000000..84ab5341 --- /dev/null +++ b/client/debug.h @@ -0,0 +1,27 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include +#include +#include +#include +#include + +class Debug +{ +public: + static bool init(); + static bool openLogsFolder(); + static QString appLogFileNamePath(); + +private: + static QString userLogsDir(); + + static QFile m_file; + static QTextStream m_textStream; + static QString m_logFileName; + + friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); +}; + +#endif // DEBUG_H diff --git a/client/defines.h b/client/defines.h new file mode 100644 index 00000000..4f244d90 --- /dev/null +++ b/client/defines.h @@ -0,0 +1,9 @@ +#ifndef DEFINES_H +#define DEFINES_H + +#define APPLICATION_NAME "AmneziaVPN" +#define SERVICE_NAME "AmneziaVPN-service" +#define ORGANIZATION_NAME "AmneziaVPN.ORG" +#define APP_VERSION "1.0.0.0" + +#endif // DEFINES_H diff --git a/client/fonts/Lato-Black.ttf b/client/fonts/Lato-Black.ttf new file mode 100644 index 00000000..a87109f5 Binary files /dev/null and b/client/fonts/Lato-Black.ttf differ diff --git a/client/fonts/Lato-BlackItalic.ttf b/client/fonts/Lato-BlackItalic.ttf new file mode 100644 index 00000000..505e23fa Binary files /dev/null and b/client/fonts/Lato-BlackItalic.ttf differ diff --git a/client/fonts/Lato-Bold.ttf b/client/fonts/Lato-Bold.ttf new file mode 100644 index 00000000..59c48434 Binary files /dev/null and b/client/fonts/Lato-Bold.ttf differ diff --git a/client/fonts/Lato-BoldItalic.ttf b/client/fonts/Lato-BoldItalic.ttf new file mode 100644 index 00000000..3371a4bf Binary files /dev/null and b/client/fonts/Lato-BoldItalic.ttf differ diff --git a/client/fonts/Lato-Hairline.ttf b/client/fonts/Lato-Hairline.ttf new file mode 100644 index 00000000..bc06473a Binary files /dev/null and b/client/fonts/Lato-Hairline.ttf differ diff --git a/client/fonts/Lato-HairlineItalic.ttf b/client/fonts/Lato-HairlineItalic.ttf new file mode 100644 index 00000000..d680800a Binary files /dev/null and b/client/fonts/Lato-HairlineItalic.ttf differ diff --git a/client/fonts/Lato-Heavy.ttf b/client/fonts/Lato-Heavy.ttf new file mode 100644 index 00000000..4a56a97c Binary files /dev/null and b/client/fonts/Lato-Heavy.ttf differ diff --git a/client/fonts/Lato-HeavyItalic.ttf b/client/fonts/Lato-HeavyItalic.ttf new file mode 100644 index 00000000..b25f78d1 Binary files /dev/null and b/client/fonts/Lato-HeavyItalic.ttf differ diff --git a/client/fonts/Lato-Italic.ttf b/client/fonts/Lato-Italic.ttf new file mode 100644 index 00000000..9babe6a8 Binary files /dev/null and b/client/fonts/Lato-Italic.ttf differ diff --git a/client/fonts/Lato-Light.ttf b/client/fonts/Lato-Light.ttf new file mode 100644 index 00000000..ccba01a9 Binary files /dev/null and b/client/fonts/Lato-Light.ttf differ diff --git a/client/fonts/Lato-LightItalic.ttf b/client/fonts/Lato-LightItalic.ttf new file mode 100644 index 00000000..fd58065e Binary files /dev/null and b/client/fonts/Lato-LightItalic.ttf differ diff --git a/client/fonts/Lato-Medium.ttf b/client/fonts/Lato-Medium.ttf new file mode 100644 index 00000000..a208b991 Binary files /dev/null and b/client/fonts/Lato-Medium.ttf differ diff --git a/client/fonts/Lato-MediumItalic.ttf b/client/fonts/Lato-MediumItalic.ttf new file mode 100644 index 00000000..ac0ee4c9 Binary files /dev/null and b/client/fonts/Lato-MediumItalic.ttf differ diff --git a/client/fonts/Lato-Regular.ttf b/client/fonts/Lato-Regular.ttf new file mode 100644 index 00000000..f01f5589 Binary files /dev/null and b/client/fonts/Lato-Regular.ttf differ diff --git a/client/fonts/Lato-Semibold.ttf b/client/fonts/Lato-Semibold.ttf new file mode 100644 index 00000000..0b95c643 Binary files /dev/null and b/client/fonts/Lato-Semibold.ttf differ diff --git a/client/fonts/Lato-SemiboldItalic.ttf b/client/fonts/Lato-SemiboldItalic.ttf new file mode 100644 index 00000000..ed70b675 Binary files /dev/null and b/client/fonts/Lato-SemiboldItalic.ttf differ diff --git a/client/fonts/Lato-Thin.ttf b/client/fonts/Lato-Thin.ttf new file mode 100644 index 00000000..ca2cc0de Binary files /dev/null and b/client/fonts/Lato-Thin.ttf differ diff --git a/client/fonts/Lato-ThinItalic.ttf b/client/fonts/Lato-ThinItalic.ttf new file mode 100644 index 00000000..1e319da5 Binary files /dev/null and b/client/fonts/Lato-ThinItalic.ttf differ diff --git a/client/images/AmneziaVPN.png b/client/images/AmneziaVPN.png new file mode 100644 index 00000000..84c395c5 Binary files /dev/null and b/client/images/AmneziaVPN.png differ diff --git a/client/images/app.icns b/client/images/app.icns new file mode 100644 index 00000000..17d67ff2 Binary files /dev/null and b/client/images/app.icns differ diff --git a/client/images/app.ico b/client/images/app.ico new file mode 100644 index 00000000..e64d04d5 Binary files /dev/null and b/client/images/app.ico differ diff --git a/client/images/arrow_left.png b/client/images/arrow_left.png new file mode 100644 index 00000000..3a4d149d Binary files /dev/null and b/client/images/arrow_left.png differ diff --git a/client/images/background_connected.png b/client/images/background_connected.png new file mode 100644 index 00000000..7e83c851 Binary files /dev/null and b/client/images/background_connected.png differ diff --git a/client/images/close.png b/client/images/close.png new file mode 100644 index 00000000..2fc5db3e Binary files /dev/null and b/client/images/close.png differ diff --git a/client/images/connect_button_connected.png b/client/images/connect_button_connected.png new file mode 100644 index 00000000..171eb79e Binary files /dev/null and b/client/images/connect_button_connected.png differ diff --git a/client/images/connect_button_disconnected.png b/client/images/connect_button_disconnected.png new file mode 100644 index 00000000..a88e26e4 Binary files /dev/null and b/client/images/connect_button_disconnected.png differ diff --git a/client/images/controls/check_off.png b/client/images/controls/check_off.png new file mode 100644 index 00000000..0a7fbf70 Binary files /dev/null and b/client/images/controls/check_off.png differ diff --git a/client/images/controls/check_on.png b/client/images/controls/check_on.png new file mode 100644 index 00000000..8b3b683b Binary files /dev/null and b/client/images/controls/check_on.png differ diff --git a/client/images/controls/radio_off.png b/client/images/controls/radio_off.png new file mode 100644 index 00000000..685980bd Binary files /dev/null and b/client/images/controls/radio_off.png differ diff --git a/client/images/controls/radio_on.png b/client/images/controls/radio_on.png new file mode 100644 index 00000000..48560e53 Binary files /dev/null and b/client/images/controls/radio_on.png differ diff --git a/client/images/download.png b/client/images/download.png new file mode 100644 index 00000000..0e949133 Binary files /dev/null and b/client/images/download.png differ diff --git a/client/images/favorites_disabled.png b/client/images/favorites_disabled.png new file mode 100644 index 00000000..12a821ac Binary files /dev/null and b/client/images/favorites_disabled.png differ diff --git a/client/images/favorites_enabled.png b/client/images/favorites_enabled.png new file mode 100644 index 00000000..61e28f42 Binary files /dev/null and b/client/images/favorites_enabled.png differ diff --git a/client/images/favorites_hover.png b/client/images/favorites_hover.png new file mode 100644 index 00000000..71e7a1b2 Binary files /dev/null and b/client/images/favorites_hover.png differ diff --git a/client/images/icon.png b/client/images/icon.png new file mode 100644 index 00000000..b7d5d423 Binary files /dev/null and b/client/images/icon.png differ diff --git a/client/images/line.png b/client/images/line.png new file mode 100644 index 00000000..c5a3a466 Binary files /dev/null and b/client/images/line.png differ diff --git a/client/images/min.png b/client/images/min.png new file mode 100644 index 00000000..cacc4fec Binary files /dev/null and b/client/images/min.png differ diff --git a/client/images/server_settings.png b/client/images/server_settings.png new file mode 100644 index 00000000..fddc8b1a Binary files /dev/null and b/client/images/server_settings.png differ diff --git a/client/images/settings.png b/client/images/settings.png new file mode 100644 index 00000000..60127b5c Binary files /dev/null and b/client/images/settings.png differ diff --git a/client/images/share.png b/client/images/share.png new file mode 100644 index 00000000..e1451e06 Binary files /dev/null and b/client/images/share.png differ diff --git a/client/images/tray/active.png b/client/images/tray/active.png new file mode 100644 index 00000000..632ee3a2 Binary files /dev/null and b/client/images/tray/active.png differ diff --git a/client/images/tray/default.png b/client/images/tray/default.png new file mode 100644 index 00000000..1e7dfd39 Binary files /dev/null and b/client/images/tray/default.png differ diff --git a/client/images/tray/error.png b/client/images/tray/error.png new file mode 100644 index 00000000..56efcce1 Binary files /dev/null and b/client/images/tray/error.png differ diff --git a/client/images/upload.png b/client/images/upload.png new file mode 100644 index 00000000..185e7a7b Binary files /dev/null and b/client/images/upload.png differ diff --git a/client/localclient.cpp b/client/localclient.cpp new file mode 100644 index 00000000..e960be73 --- /dev/null +++ b/client/localclient.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include "localclient.h" + +LocalClient::LocalClient(QObject *parent) : QObject(parent), + m_socket(new QLocalSocket(this)) +{ + m_in.setDevice(m_socket); + m_in.setVersion(QDataStream::Qt_5_10); + + connect(m_socket, &QLocalSocket::readyRead, this, &LocalClient::onReadyRead); + connect(m_socket, &QLocalSocket::connected, this, &LocalClient::onConnected); + connect(m_socket, QOverload::of(&QLocalSocket::error), this, &LocalClient::displayError); +} + +void LocalClient::connectToServer(const QString& name) +{ + m_blockSize = 0; + m_socket->abort(); + m_socket->connectToServer(name); +} + +QString LocalClient::serverName() const +{ + return m_socket->serverName(); +} + +void LocalClient::onConnected() +{ + emit connected(); +} + +bool LocalClient::connectedState() const +{ + return (m_socket->state() == QLocalSocket::ConnectedState); +} + +quint64 LocalClient::write(const QByteArray& data) +{ + return m_socket->write(data); +} + +void LocalClient::onReadyRead() +{ + if (m_socket->canReadLine()) { + char buf[1024]; + qint64 lineLength = m_socket->readLine(buf, sizeof(buf)); + if (lineLength != -1) { + QString line = buf; + line = line.simplified(); + qDebug().noquote() << QString("Readed line: '%1'").arg(line); + emit lineAvailable(line); + } + } +} + +void LocalClient::displayError(QLocalSocket::LocalSocketError socketError) +{ + Q_UNUSED(socketError) + qDebug().noquote() << QString("The following error occurred: %1.").arg(m_socket->errorString()); +} diff --git a/client/localclient.h b/client/localclient.h new file mode 100644 index 00000000..cd66af7a --- /dev/null +++ b/client/localclient.h @@ -0,0 +1,34 @@ +#ifndef LOCALCLIENT_H +#define LOCALCLIENT_H + +#include +#include + +class LocalClient : public QObject +{ + Q_OBJECT + +public: + explicit LocalClient(QObject *parent = nullptr); + + QString serverName() const; + bool connectedState() const; + quint64 write(const QByteArray& data); + void connectToServer(const QString& name); + +signals: + void connected(); + void lineAvailable(const QString& line); + +private slots: + void displayError(QLocalSocket::LocalSocketError socketError); + void onConnected(); + void onReadyRead(); + +private: + QLocalSocket* m_socket; + QDataStream m_in; + quint32 m_blockSize; +}; + +#endif // LOCALCLIENT_H diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 00000000..ee6bb3f7 --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +#include "debug.h" +#include "defines.h" +#include "runguard.h" + +#include "ui/mainwindow.h" + +static void loadTranslator() +{ + QTranslator* translator = new QTranslator; + if (translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) { + qApp->installTranslator(translator); + } +} + +int main(int argc, char *argv[]) +{ + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); + RunGuard::instance(APPLICATION_NAME).activate(); + + QApplication app(argc, argv); + loadTranslator(); + + if (!RunGuard::instance().tryToRun()) { + qDebug() << "Tried to run second instance. Exiting..."; + QMessageBox::information(NULL, QObject::tr("Notification"), QObject::tr("AmneziaVPN is already running.")); + return 0; + } + + QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf"); + + app.setApplicationName(APPLICATION_NAME); + app.setOrganizationName(ORGANIZATION_NAME); + app.setApplicationDisplayName(APPLICATION_NAME); + + QCommandLineParser parser; + parser.setApplicationDescription(APPLICATION_NAME); + parser.addHelpOption(); + parser.addVersionOption(); + + if (!Debug::init()) { + qWarning() << "Initialization of debug subsystem failed"; + } + + QFont f("Lato Regular", 10); + f.setStyleStrategy(QFont::PreferAntialias); + app.setFont(f); + + MainWindow mainWindow; + mainWindow.show(); + + return app.exec(); +} diff --git a/client/managementserver.cpp b/client/managementserver.cpp new file mode 100644 index 00000000..9330f046 --- /dev/null +++ b/client/managementserver.cpp @@ -0,0 +1,111 @@ +#include +#include +#include + +#include "managementserver.h" + +ManagementServer::ManagementServer(QObject *parent) : QObject(parent), + m_tcpServer(nullptr) +{ + +} + +ManagementServer::~ManagementServer() +{ + +} + +bool ManagementServer::isOpen() const +{ + return (m_socket && m_socket->isOpen()); +} + +void ManagementServer::stop() +{ + m_tcpServer->close(); +} + +void ManagementServer::onAcceptError(QAbstractSocket::SocketError socketError) +{ + qDebug().noquote() << QString("Accept error: %1").arg(socketError); +} + +qint64 ManagementServer::writeCommand(const QString& message) +{ + if (!isOpen()) { + return 0; + } + + const QString command = message + "\n"; + return m_socket->write(command.toStdString().c_str()); +} + +void ManagementServer::onNewConnection() +{ + qDebug() << "New incoming connection"; + + m_socket = m_tcpServer->nextPendingConnection(); + m_tcpServer->close(); + + QObject::connect(m_socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + QObject::connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); + QObject::connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); +} + +void ManagementServer::onSocketError(QAbstractSocket::SocketError socketError) +{ + Q_UNUSED(socketError); + + qDebug().noquote() << QString("Mananement server error: %1").arg(m_socket->errorString()); +} + +void ManagementServer::onSocketDisconnected() +{ + m_socket->deleteLater(); +} + +QTcpSocket* ManagementServer::socket() const +{ + if (!isOpen()) { + return nullptr; + } + return m_socket; +} + +void ManagementServer::onReadyRead() +{ + emit readyRead(); +} + +bool ManagementServer::start(const QString& host, unsigned int port) +{ + if (m_tcpServer) { + delete m_tcpServer; + } + + m_tcpServer = new QTcpServer(this); + m_tcpServer->setMaxPendingConnections(1); + + connect(m_tcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(onAcceptError(QAbstractSocket::SocketError))); + connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection())); + + if (m_tcpServer->listen(QHostAddress(host), port)) { + emit serverStarted(); + return true; + } + + qDebug().noquote() << QString("Can't start TCP server, %1,%2") + .arg(m_tcpServer->serverError()) + .arg(m_tcpServer->errorString()); + return false; +} + +QString ManagementServer::readLine() +{ + if (!isOpen()) { + qDebug() << "Socket is not opened"; + return QString(); + } + + return m_socket->readLine(); +} diff --git a/client/managementserver.h b/client/managementserver.h new file mode 100644 index 00000000..bb91c3aa --- /dev/null +++ b/client/managementserver.h @@ -0,0 +1,43 @@ +#ifndef MANAGEMENTSERVER_H +#define MANAGEMENTSERVER_H + +#include +#include + +class QTcpServer; +class QTcpSocket; + +class ManagementServer : public QObject +{ + Q_OBJECT + +public: + explicit ManagementServer(QObject *parent = nullptr); + ~ManagementServer(); + + bool start(const QString& host, unsigned int port); + void stop(); + bool isOpen() const; + + QString readLine(); + qint64 writeCommand(const QString& message); + + QTcpSocket* socket() const; + +signals: + void readyRead(); + void serverStarted(); + +protected slots: + void onAcceptError(QAbstractSocket::SocketError socketError); + void onNewConnection(); + void onReadyRead(); + void onSocketDisconnected(); + void onSocketError(QAbstractSocket::SocketError socketError); + +protected: + QTcpServer* m_tcpServer; + QTcpSocket* m_socket; +}; + +#endif // MANAGEMENTSERVER_H diff --git a/client/message.cpp b/client/message.cpp new file mode 100644 index 00000000..eb23cda4 --- /dev/null +++ b/client/message.cpp @@ -0,0 +1,95 @@ +#include "message.h" + +Message::Message(State state, const QStringList& args) : + m_valid(true), + m_state(state), + m_args(args) +{ + +} + +bool Message::isValid() const +{ + return m_valid; +} + +QString Message::textState() const +{ + switch (m_state) { + case State::Unknown: return "Unknown"; + case State::Initialize: return "Initialize"; + case State::StartRequest: return "StartRequest"; + case State::Started: return "Started"; + case State::FinishRequest: return "FinishRequest"; + case State::Finished: return "Finished"; + default: + ; + } + return QString(); +} + +Message::State Message::state() const +{ + return m_state; +} + +QString Message::toString() const +{ + if (!isValid()) { + return QString(); + } + + return QString("%1%2%3") + .arg(textState()) + .arg(m_dataSeparator) + .arg(argsToString()); +} + +QString Message::argAtIndex(int index) const +{ + if ((index + 1) > args().size()) { + return QString(); + } + + return args().at(index); +} + +QStringList Message::args() const +{ + return m_args; +} + +QString Message::argsToString() const +{ + return m_args.join(m_argSeparator); +} + +Message::Message(const QString& data) +{ + m_valid = false; + if (data.isEmpty()) { + return; + } + + QStringList dataList = data.split(m_dataSeparator); + if ((dataList.size() != 2)) { + return; + } + + bool stateFound = false; + for (int i = static_cast(State::Unknown); i <= static_cast(State::Finished); i++ ) { + m_state = static_cast(i); + if (textState() == dataList.at(0)) { + stateFound = true; + break; + } + } + + if (!stateFound) { + return; + } + + m_args = dataList.at(1).split(m_argSeparator); + m_valid = true; +} + diff --git a/client/message.h b/client/message.h new file mode 100644 index 00000000..46eed2a5 --- /dev/null +++ b/client/message.h @@ -0,0 +1,31 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include + +class Message { + +public: + enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished}; + Message(State state, const QStringList& args); + Message(const QString& data); + + QString argAtIndex(int index) const; + QString argsToString() const; + QString toString() const; + QStringList args() const; + State state() const; + bool isValid() const; + +protected: + QString textState() const; + + const QString m_argSeparator = ","; + const QString m_dataSeparator = "|"; + + bool m_valid; + State m_state; + QStringList m_args; +}; + +#endif // MESSAGE_H diff --git a/client/platform_win/vpnclient.rc b/client/platform_win/vpnclient.rc new file mode 100644 index 00000000..7b0155b0 --- /dev/null +++ b/client/platform_win/vpnclient.rc @@ -0,0 +1,48 @@ +#include +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +IDI_ICON1 ICON "../images/app.ico" + +#define VER_FILEVERSION 1,1,1,1 +#define VER_FILEVERSION_STR "1.1.1.1\0" + +#define VER_PRODUCTVERSION 1,1,1,1 +#define VER_PRODUCTVERSION_STR "1.1.1.1\0" + +#define VER_COMPANYNAME_STR "AmneziaVPN" +#define VER_FILEDESCRIPTION_STR "AmneziaVPN" +#define VER_INTERNALNAME_STR "AmneziaVPN" +#define VER_LEGALCOPYRIGHT_STR "AmneziaVPN." +#define VER_LEGALTRADEMARKS1_STR "All Rights Reserved" +#define VER_LEGALTRADEMARKS2_STR VER_LEGALTRADEMARKS1_STR +#define VER_ORIGINALFILENAME_STR "amneziavpn.exe" +#define VER_PRODUCTNAME_STR "AmneziaVPN" + +#define VER_COMPANYDOMAIN_STR "http://amnezia.org/" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", VER_FILEDESCRIPTION_STR + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", VER_INTERNALNAME_STR + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR + VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR + VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR + VALUE "ProductName", VER_PRODUCTNAME_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp new file mode 100644 index 00000000..41f4d65d --- /dev/null +++ b/client/protocols/openvpnprotocol.cpp @@ -0,0 +1,241 @@ +#include +#include + +#include "communicator.h" +#include "debug.h" +#include "openvpnprotocol.h" +#include "utils.h" + + +OpenVpnProtocol::OpenVpnProtocol(const QString& args, QObject* parent) : + VpnProtocol(args, parent), + m_requestFromUserToStop(false) +{ + setConfigFile(args); + connect(m_communicator, &Communicator::messageReceived, this, &OpenVpnProtocol::onMessageReceived); + connect(&m_managementServer, &ManagementServer::readyRead, this, &OpenVpnProtocol::onReadyReadDataFromManagementServer); +} + +OpenVpnProtocol::~OpenVpnProtocol() +{ + stop(); +} + +void OpenVpnProtocol::onMessageReceived(const Message& message) +{ + if (!message.isValid()) { + qWarning().noquote() << QString("Message received: '%1', but it is not valid").arg(message.toString()); + return; + } + + switch (message.state()) { + case Message::State::Started: + qDebug() << "OpenVPN process started"; + break; + case Message::State::Finished: + qDebug().noquote() << QString("OpenVPN process finished with status %1").arg(message.argAtIndex(1)); + onOpenVpnProcessFinished(message.argAtIndex(1).toInt()); + break; + default: + qDebug().noquote() << QString("Message received: '%1'").arg(message.toString()); + ; + } +} + +void OpenVpnProtocol::stop() +{ + if ((m_connectionState == VpnProtocol::ConnectionState::Preparing) || + (m_connectionState == VpnProtocol::ConnectionState::Connecting) || + (m_connectionState == VpnProtocol::ConnectionState::Connected)) { + if (!sendTermSignal()) { + killOpenVpnProcess(); + } + setConnectionState(VpnProtocol::ConnectionState::Disconnecting); + } +} + +void OpenVpnProtocol::killOpenVpnProcess() +{ + // send command to kill openvpn process (if any). +} + +bool OpenVpnProtocol::setConfigFile(const QString& configFileNamePath) +{ + m_configFileName = configFileNamePath; + QFileInfo file(m_configFileName); + + if (file.fileName().isEmpty()) { + m_configFileName = Utils::defaultVpnConfigFileName(); + } + + if (m_configFileName.isEmpty()) { + return false; + } + + qDebug().noquote() << QString("Set config file: '%1'").arg(configPath()); + + return false; +} + +bool OpenVpnProtocol::openVpnProcessIsRunning() const +{ + return Utils::processIsRunning("openvpn"); +} + +void OpenVpnProtocol::disconnectFromManagementServer() +{ + m_managementServer.stop(); +} + +QString OpenVpnProtocol::configPath() const +{ + return m_configFileName; +} + +void OpenVpnProtocol::writeCommand(const QString& command) +{ + QTextStream stream(reinterpret_cast(m_managementServer.socket())); + stream << command << endl; +} + +QString OpenVpnProtocol::openVpnExecPath() const +{ +#ifdef Q_OS_WIN + return Utils::executable(QString("openvpn/%1/openvpn").arg(QSysInfo::buildCpuArchitecture()), true); +#else + return Utils::executable(QString("/openvpn"), true); +#endif +} + +ErrorCode OpenVpnProtocol::start() +{ + qDebug() << "Start OpenVPN connection"; + + m_requestFromUserToStop = false; + m_openVpnStateSigTermHandlerTimer.stop(); + stop(); + + if (communicator() && !communicator()->connected()) { + setLastError(ErrorCode::AmneziaServiceConnectionFailed); + return lastError(); + } + + if (!QFileInfo::exists(openVpnExecPath())) { + setLastError(ErrorCode::OpenVpnExecutableMissing); + return lastError(); + } + + if (!QFileInfo::exists(configPath())) { + setLastError(ErrorCode::OpenVpnConfigMissing); + return lastError(); + } + + QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log"; + Utils::createEmptyFile(vpnLogFileNamePath); + + QStringList args({openVpnExecPath(), + "--config" , configPath(), + "--management", m_managementHost, QString::number(m_managementPort), + "--management-client", + "--log-append", vpnLogFileNamePath + }); + + if (!m_managementServer.start(m_managementHost, m_managementPort)) { + setLastError(ErrorCode::OpenVpnManagementServerError); + return lastError(); + } + + setConnectionState(ConnectionState::Connecting); + m_communicator->sendMessage(Message(Message::State::StartRequest, args)); + startTimeoutTimer(); + + return ErrorCode::NoError; +} + +void OpenVpnProtocol::openVpnStateSigTermHandlerTimerEvent() +{ + bool processStatus = openVpnProcessIsRunning(); + if (processStatus) { + killOpenVpnProcess(); + } + onOpenVpnProcessFinished(0); +} + +void OpenVpnProtocol::openVpnStateSigTermHandler() +{ + m_openVpnStateSigTermHandlerTimer.start(5000); +} + +bool OpenVpnProtocol::sendTermSignal() +{ + return m_managementServer.writeCommand("signal SIGTERM"); +} + +void OpenVpnProtocol::sendByteCount() +{ + m_managementServer.writeCommand("bytecount 1"); +} + +void OpenVpnProtocol::sendInitialData() +{ + m_managementServer.writeCommand("state on"); + m_managementServer.writeCommand("log on"); +} + +void OpenVpnProtocol::onReadyReadDataFromManagementServer() +{ + for (;;) { + QString line = m_managementServer.readLine().simplified(); + + if (line.isEmpty()) { + return; + } + + if (!line.contains(">BYTECOUNT")) { + qDebug().noquote() << line; + } + + if (line.contains(">INFO:OpenVPN Management Interface")) { + sendInitialData(); + } else if (line.startsWith(">STATE")) { + if (line.contains("CONNECTED,SUCCESS")) { + sendByteCount(); + stopTimeoutTimer(); + setConnectionState(VpnProtocol::ConnectionState::Connected); + continue; + } else if (line.contains("EXITING,SIGTER")) { + openVpnStateSigTermHandler(); + continue; + } + } + + QByteArray data(line.toStdString().c_str()); + if (data.contains(">BYTECOUNT:")) { + int beg = data.lastIndexOf(">BYTECOUNT:"); + int end = data.indexOf("\n", beg); + + beg += sizeof(">BYTECOUNT:") - 1; + QList count = data.mid(beg, end - beg + 1).split(','); + + quint64 r = static_cast(count.at(0).trimmed().toULongLong()); + quint64 s = static_cast(count.at(1).trimmed().toULongLong()); + + setBytesChanged(r, s); + } + } +} + +void OpenVpnProtocol::onOpenVpnProcessFinished(int exitCode) +{ + m_openVpnStateSigTermHandlerTimer.stop(); + if (m_connectionState == VpnProtocol::ConnectionState::Disconnected) { + qDebug() << "Already in disconnected state"; + return; + } + + qDebug().noquote() << QString("Process finished with code: %1").arg(exitCode); + + setConnectionState(VpnProtocol::ConnectionState::Disconnected); +} + + diff --git a/client/protocols/openvpnprotocol.h b/client/protocols/openvpnprotocol.h new file mode 100644 index 00000000..9bf1fbbf --- /dev/null +++ b/client/protocols/openvpnprotocol.h @@ -0,0 +1,51 @@ +#ifndef OPENVPNPROTOCOL_H +#define OPENVPNPROTOCOL_H + +#include +#include +#include + +#include "managementserver.h" +#include "message.h" +#include "vpnprotocol.h" + +class OpenVpnProtocol : public VpnProtocol +{ + Q_OBJECT + +public: + explicit OpenVpnProtocol(const QString& args = QString(), QObject* parent = nullptr); + ~OpenVpnProtocol(); + + ErrorCode start() override; + void stop() override; + +protected slots: + void onMessageReceived(const Message& message); + void onOpenVpnProcessFinished(int exitCode); + void onReadyReadDataFromManagementServer(); + +protected: + QString configPath() const; + QString openVpnExecPath() const; + bool openVpnProcessIsRunning() const; + bool sendTermSignal(); + bool setConfigFile(const QString& configFileNamePath); + void disconnectFromManagementServer(); + void killOpenVpnProcess(); + void openVpnStateSigTermHandler(); + void openVpnStateSigTermHandlerTimerEvent(); + void sendByteCount(); + void sendInitialData(); + void writeCommand(const QString& command); + + const QString m_managementHost = "127.0.0.1"; + const unsigned int m_managementPort = 57775; + + ManagementServer m_managementServer; + QString m_configFileName; + QTimer m_openVpnStateSigTermHandlerTimer; + bool m_requestFromUserToStop; +}; + +#endif // OPENVPNPROTOCOL_H diff --git a/client/protocols/vpnprotocol.cpp b/client/protocols/vpnprotocol.cpp new file mode 100644 index 00000000..5e9c35ba --- /dev/null +++ b/client/protocols/vpnprotocol.cpp @@ -0,0 +1,124 @@ +#include +#include + +#include "communicator.h" +#include "vpnprotocol.h" + +Communicator* VpnProtocol::m_communicator = nullptr; + +VpnProtocol::VpnProtocol(const QString& args, QObject* parent) + : QObject(parent), + m_connectionState(ConnectionState::Unknown), + m_timeoutTimer(new QTimer(this)), + m_receivedBytes(0), + m_sentBytes(0) +{ + m_timeoutTimer->setSingleShot(true); + connect(m_timeoutTimer, &QTimer::timeout, this, &VpnProtocol::onTimeout); + + Q_UNUSED(args) +} + +void VpnProtocol::initializeCommunicator(QObject* parent) +{ + if (!m_communicator) { + m_communicator = new Communicator(parent); + } +} + +Communicator* VpnProtocol::communicator() +{ + return m_communicator; +} + +void VpnProtocol::setLastError(ErrorCode lastError) +{ + m_lastError = lastError; + qCritical().noquote() << m_lastError; +} + +ErrorCode VpnProtocol::lastError() const +{ + return m_lastError; +} + +void VpnProtocol::onTimeout() +{ + qDebug() << "Timeout"; + + emit timeoutTimerEvent(); + stop(); +} + +void VpnProtocol::startTimeoutTimer() +{ + m_timeoutTimer->start(30000); +} + +void VpnProtocol::stopTimeoutTimer() +{ + m_timeoutTimer->stop(); +} + +VpnProtocol::ConnectionState VpnProtocol::connectionState() const +{ + return m_connectionState; +} + +void VpnProtocol::setBytesChanged(quint64 receivedBytes, quint64 sentBytes) +{ + emit bytesChanged(receivedBytes - m_receivedBytes, sentBytes - m_sentBytes); + + m_receivedBytes = receivedBytes; + m_sentBytes = sentBytes; +} + +void VpnProtocol::setConnectionState(VpnProtocol::ConnectionState state) +{ + if (m_connectionState == state) { + return; + } + + m_connectionState = state; + if (m_connectionState == ConnectionState::Disconnected) { + m_receivedBytes = 0; + m_sentBytes = 0; + } + + qDebug().noquote() << QString("Connection state: '%1'").arg(textConnectionState()); + + emit connectionStateChanged(m_connectionState); +} + +QString VpnProtocol::textConnectionState(ConnectionState connectionState) +{ + switch (connectionState) { + case ConnectionState::Unknown: return "Unknown"; + case ConnectionState::Disconnected: return "Disconnected"; + case ConnectionState::Preparing: return "Preparing"; + case ConnectionState::Connecting: return "Connecting"; + case ConnectionState::Connected: return "Connected"; + case ConnectionState::Disconnecting: return "Disconnecting"; + case ConnectionState::TunnelReconnecting: return "TunnelReconnecting"; + case ConnectionState::Error: return "Error"; + default: + ; + } + + return QString(); +} + +QString VpnProtocol::textConnectionState() const +{ + return textConnectionState(m_connectionState); +} + +bool VpnProtocol::connected() const +{ + return m_connectionState == ConnectionState::Connected; +} + +bool VpnProtocol::disconnected() const +{ + return m_connectionState == ConnectionState::Disconnected; +} diff --git a/client/protocols/vpnprotocol.h b/client/protocols/vpnprotocol.h new file mode 100644 index 00000000..3472afdf --- /dev/null +++ b/client/protocols/vpnprotocol.h @@ -0,0 +1,64 @@ +#ifndef VPNPROTOCOL_H +#define VPNPROTOCOL_H + +#include +#include + +#include "core/defs.h" +using namespace amnezia; + +class QTimer; +class Communicator; + +class VpnProtocol : public QObject +{ + Q_OBJECT + +public: + explicit VpnProtocol(const QString& args = QString(), QObject* parent = nullptr); + virtual ~VpnProtocol() override = default; + + enum class ConnectionState {Unknown, Disconnected, Preparing, Connecting, Connected, Disconnecting, TunnelReconnecting, Error}; + + static Communicator* communicator(); + static QString textConnectionState(ConnectionState connectionState); + static void initializeCommunicator(QObject* parent = nullptr); + + + virtual bool connected() const; + virtual bool disconnected() const; + virtual ErrorCode start() = 0; + virtual void stop() = 0; + + ConnectionState connectionState() const; + ErrorCode lastError() const; + QString textConnectionState() const; + void setLastError(ErrorCode lastError); + +signals: + void bytesChanged(quint64 receivedBytes, quint64 sentBytes); + void connectionStateChanged(VpnProtocol::ConnectionState state); + void timeoutTimerEvent(); + +protected slots: + virtual void onTimeout(); + +protected: + void startTimeoutTimer(); + void stopTimeoutTimer(); + + virtual void setBytesChanged(quint64 receivedBytes, quint64 sentBytes); + virtual void setConnectionState(VpnProtocol::ConnectionState state); + + static Communicator* m_communicator; + + ConnectionState m_connectionState; + +private: + QTimer* m_timeoutTimer; + ErrorCode m_lastError; + quint64 m_receivedBytes; + quint64 m_sentBytes; +}; + +#endif // VPNPROTOCOL_H diff --git a/client/resources.qrc b/client/resources.qrc new file mode 100644 index 00000000..ec0b46a2 --- /dev/null +++ b/client/resources.qrc @@ -0,0 +1,42 @@ + + + translations/amneziavpn_ru.qm + images/close.png + images/settings.png + images/min.png + images/favorites_disabled.png + images/favorites_enabled.png + images/favorites_hover.png + images/controls/check_off.png + images/controls/check_on.png + images/controls/radio_off.png + images/controls/radio_on.png + images/download.png + images/upload.png + images/tray/active.png + images/tray/default.png + images/tray/error.png + images/arrow_left.png + images/connect_button_connected.png + images/connect_button_disconnected.png + fonts/Lato-Black.ttf + fonts/Lato-BlackItalic.ttf + fonts/Lato-Bold.ttf + fonts/Lato-BoldItalic.ttf + fonts/Lato-Italic.ttf + fonts/Lato-Light.ttf + fonts/Lato-LightItalic.ttf + fonts/Lato-Regular.ttf + fonts/Lato-Thin.ttf + fonts/Lato-ThinItalic.ttf + images/AmneziaVPN.png + images/line.png + images/server_settings.png + images/share.png + server_scripts/remove_openvpn_server.sh + server_scripts/setup_openvpn_server.sh + server_scripts/template.ovpn + images/background_connected.png + server_scripts/setup_shadowsocks_server.sh + + diff --git a/client/runguard.cpp b/client/runguard.cpp new file mode 100644 index 00000000..729c7ece --- /dev/null +++ b/client/runguard.cpp @@ -0,0 +1,88 @@ +#include "runguard.h" +#include + +namespace +{ + +QString generateKeyHash( const QString& key, const QString& salt ) +{ + QByteArray data; + + data.append( key.toUtf8() ); + data.append( salt.toUtf8() ); + data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); + + return data; +} + +} + +RunGuard::RunGuard(const QString& key) + : key( key ) + , memLockKey( generateKeyHash( key, "_memLockKey" ) ) + , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) + , sharedMem( sharedmemKey ) + , memLock( memLockKey, 1 ) +{ + qDebug() << "RunGuard::RunGuard key" << key; +} + +RunGuard &RunGuard::instance(const QString& key) +{ + static RunGuard s(key); + return s; +} + +void RunGuard::activate() +{ + memLock.acquire(); + { + QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/ + fix.attach(); + } + memLock.release(); +} + +RunGuard::~RunGuard() +{ + release(); +} + +bool RunGuard::isAnotherRunning() const +{ + if ( sharedMem.isAttached() ) + return false; + + memLock.acquire(); + const bool isRunning = sharedMem.attach(); + if ( isRunning ) + sharedMem.detach(); + memLock.release(); + + return isRunning; +} + +bool RunGuard::tryToRun() +{ + if ( isAnotherRunning() ) // Extra check + return false; + + memLock.acquire(); + const bool result = sharedMem.create( sizeof( quint64 ) ); + memLock.release(); + if ( !result ) + { + release(); + return false; + } + + return true; +} + +void RunGuard::release() +{ + memLock.acquire(); + if ( sharedMem.isAttached() ) + sharedMem.detach(); + memLock.release(); +} diff --git a/client/runguard.h b/client/runguard.h new file mode 100644 index 00000000..96df44a8 --- /dev/null +++ b/client/runguard.h @@ -0,0 +1,37 @@ +#ifndef RUNGUARD_H +#define RUNGUARD_H + +#include +#include +#include +#include + +/** + * @brief The RunGuard class - The application single instance (via shared memory) + */ +class RunGuard +{ + +public: + static RunGuard &instance(const QString& key = QString()); + + ~RunGuard(); + + void activate(); + bool isAnotherRunning() const; + bool tryToRun(); + void release(); + +private: + RunGuard(const QString& key); + Q_DISABLE_COPY( RunGuard ) + + const QString key; + const QString memLockKey; + const QString sharedmemKey; + + mutable QSharedMemory sharedMem; + mutable QSystemSemaphore memLock; + +}; +#endif // RUNGUARD_H diff --git a/client/server_scripts/remove_openvpn_server.sh b/client/server_scripts/remove_openvpn_server.sh new file mode 100644 index 00000000..3df28e07 --- /dev/null +++ b/client/server_scripts/remove_openvpn_server.sh @@ -0,0 +1,2 @@ +sudo docker stop amneziavpn +sudo docker rm -f amneziavpn diff --git a/client/server_scripts/setup_openvpn_server.sh b/client/server_scripts/setup_openvpn_server.sh new file mode 100644 index 00000000..d9b30a15 --- /dev/null +++ b/client/server_scripts/setup_openvpn_server.sh @@ -0,0 +1,24 @@ +#DOCKER_IMAGE="amneziavpn/openvpn:latest" +#CONTAINER_NAME="amneziavpn" + +#sudo apt update +sudo apt install -y docker.io curl +sudo systemctl start docker + +sudo docker stop amneziavpn +sudo docker rm -f amneziavpn +sudo docker pull amneziavpn/openvpn:latest +sudo docker run -d --restart always --cap-add=NET_ADMIN -p 1194:1194/udp --name amneziavpn amneziavpn/openvpn:latest + + +docker exec -i amneziavpn sh -c "mkdir -p /opt/amneziavpn_data/clients" + +#docker exec -i amneziavpn sh -c "cat /proc/sys/kernel/random/entropy_avail" +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && easyrsa init-pki" +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && easyrsa gen-dh" + +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && cp pki/dh.pem /etc/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req MyReq nopass << EOF2 yes EOF2" +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && easyrsa sign-req server MyReq << EOF3 yes EOF3" +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && openvpn --genkey --secret ta.key << EOF4" +docker exec -i amneziavpn sh -c "cd /opt/amneziavpn_data && cp pki/ca.crt pki/issued/MyReq.crt pki/private/MyReq.key ta.key /etc/openvpn" +docker exec -i amneziavpn sh -c "openvpn --config /etc/openvpn/server.conf &" diff --git a/client/server_scripts/setup_shadowsocks_server.sh b/client/server_scripts/setup_shadowsocks_server.sh new file mode 100644 index 00000000..46df107a --- /dev/null +++ b/client/server_scripts/setup_shadowsocks_server.sh @@ -0,0 +1,13 @@ +#DOCKER_IMAGE="amneziavpn/shadow-vpn:latest" +#CONTAINER_NAME="shadow-vpn" + +#sudo apt update +sudo apt install -y docker.io curl +sudo systemctl start docker + +sudo docker stop shadow-vpn +sudo docker rm -f shadow-vpn +sudo docker pull amneziavpn/shadow-vpn:latest +sudo docker run -d --restart always --cap-add=NET_ADMIN -p 1194:1194/tcp -p 6789:6789/tcp --name shadow-vpn amneziavpn/shadow-vpn:latest + + diff --git a/client/server_scripts/template.ovpn b/client/server_scripts/template.ovpn new file mode 100644 index 00000000..da6d43c2 --- /dev/null +++ b/client/server_scripts/template.ovpn @@ -0,0 +1,28 @@ +client +dev tun +proto $PROTO +resolv-retry infinite +nobind +persist-key +persist-tun +cipher AES-256-GCM +auth SHA512 +verb 3 +tls-client +tls-version-min 1.2 +key-direction 1 +remote-cert-tls server + +remote $REMOTE_HOST $REMOTE_PORT + +$CA_CERT + + +$CLIENT_CERT + + +$PRIV_KEY + + +$TA_KEY + diff --git a/client/settings.cpp b/client/settings.cpp new file mode 100644 index 00000000..e0062c2b --- /dev/null +++ b/client/settings.cpp @@ -0,0 +1,74 @@ +#include + +#include "defines.h" +#include "settings.h" + +Settings::Settings(QObject* parent) : QObject(parent) +{ + m_settings = new QSettings(ORGANIZATION_NAME, APPLICATION_NAME, this); + read(); +} + +void Settings::read() +{ + m_settings->beginGroup("Server"); + m_userName = m_settings->value("userName", QString()).toString(); + m_password = m_settings->value("password", QString()).toString(); + m_serverName = m_settings->value("serverName", QString()).toString(); + m_serverPort = m_settings->value("serverPort", 22).toInt(); + m_settings->endGroup(); +} + +void Settings::save() +{ + m_settings->beginGroup("Server"); + m_settings->setValue("userName", m_userName); + m_settings->setValue("password", m_password); + m_settings->setValue("serverName", m_serverName); + m_settings->setValue("serverPort", m_serverPort); + m_settings->endGroup(); +} + +bool Settings::haveAuthData() const +{ + return (!serverName().isEmpty() && !userName().isEmpty() && !password().isEmpty()); +} + +void Settings::setUserName(const QString& login) +{ + m_userName = login; +} + +void Settings::setPassword(const QString& password) +{ + m_password = password; +} + +void Settings::setServerName(const QString& serverName) +{ + m_serverName = serverName; +} + +void Settings::setServerPort(int serverPort) +{ + m_serverPort = serverPort; +} + +void Settings::setServerCredentials(const ServerCredentials &credentials) +{ + setServerName(credentials.hostName); + setServerPort(credentials.port); + setUserName(credentials.userName); + setPassword(credentials.password); +} + +ServerCredentials Settings::serverCredentials() +{ + ServerCredentials credentials; + credentials.hostName = serverName(); + credentials.userName = userName(); + credentials.password = password(); + credentials.port = serverPort(); + + return credentials; +} diff --git a/client/settings.h b/client/settings.h new file mode 100644 index 00000000..14a7aa6a --- /dev/null +++ b/client/settings.h @@ -0,0 +1,46 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +#include "core/defs.h" + +using namespace amnezia; + +class QSettings; + +class Settings : public QObject +{ + Q_OBJECT + +public: + explicit Settings(QObject* parent = nullptr); + + void read(); + void save(); + + void setUserName(const QString& login); + void setPassword(const QString& password); + void setServerName(const QString& serverName); + void setServerPort(int serverPort); + void setServerCredentials(const ServerCredentials &credentials); + + QString userName() const { return m_userName; } + QString password() const { return m_password; } + QString serverName() const { return m_serverName; } + int serverPort() const { return m_serverPort; } + ServerCredentials serverCredentials(); + + + bool haveAuthData() const; + +protected: + QSettings* m_settings; + QString m_userName; + QString m_password; + QString m_serverName; + int m_serverPort; +}; + +#endif // SETTINGS_H diff --git a/client/translations/amneziavpn_ru.qm b/client/translations/amneziavpn_ru.qm new file mode 100644 index 00000000..1da6f420 Binary files /dev/null and b/client/translations/amneziavpn_ru.qm differ diff --git a/client/translations/amneziavpn_ru.ts b/client/translations/amneziavpn_ru.ts new file mode 100644 index 00000000..1715193a --- /dev/null +++ b/client/translations/amneziavpn_ru.ts @@ -0,0 +1,638 @@ + + + + + MainWindow + + + Connect to the already created VPN server + Подключиться к уже созданному серверу VPN + + + + Connection code + Код для подключения + + + + + Connecting... + Подключение... + + + + + Connect + Подключиться + + + + Set up your own server + Настроить собственный сервер + + + + Connect your server to use VPN + Подключите ваш сервер, чтобы использовать VPN + + + + Server IP address + IP адрес сервера + + + + Login to connect via SSH + Логин для подключения по SSH + + + + Password + Пароль + + + + Where to get connection data → + Where to get connection data → + + + + + 0 Mbps + 0 Мбит/сек + + + + Add site + Добавить сайт + + + + Connected + Подключено + + + + How to use VPN + Как использовать VPN + + + + For all connections + Для всех соединений + + + + For selected sites + Для выбранных сайтов + + + + List of the most popular prohibited sites + Список самых популярных запрещенных сайтов + + + + For example, rutor.org or 17.21.111.8 + Например, rutor.org или 17.21.111.8 + + + + Anyone who logs in with this code will have the same rights to use the VPN as you. To create a new code, change your login and / or password for connection in your server settings. + Тот, кто зайдёт с этим кодом, будет иметь те же права на использование VPN, что и вы. Чтобы создать новый код смените логин и/или пароль для подлючения в настройках вашего сервера. + + + + These sites will open via VPN + These sites will open via VPN + + + + Delete selected item + Удалить выбранный элемент + + + + Hostname or IP address + Имя хоста или IP адрес + + + + + + + + + + + Server settings + Настройки сервера + + + + Share connection + Поделиться подключением + + + + Connection string + Строка подключения + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Consolas'; font-size:22px; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\aosdiufhafafsuhgqejghuserhglaidhgauhgalgadg</span></p></body></html> + + + + + Copy + Копировать + + + + Cannot open logs folder! + Невозможно открыть папку с логами! + + + + Please fill in all fields + Пожалуйста, заполните все поля + + + + QObject + + + AmneziaVPN is already running. + Приложение AmneziaVPN уже запущено. + + + + Notification + + + + + QSsh::Internal::SftpChannelPrivate + + + Server could not start SFTP subsystem. + + + + + The SFTP server finished unexpectedly with exit code %1. + + + + + The SFTP server crashed: %1. + + + + + Unexpected packet of type %1. + + + + + Protocol version mismatch: Expected %1, got %2 + + + + + Unknown error. + + + + + Created remote directory "%1". + + + + + Remote directory "%1" already exists. + + + + + Error creating directory "%1": %2 + + + + + Could not open local file "%1": %2 + + + + + Remote directory could not be opened for reading. + + + + + Failed to list remote directory contents. + + + + + Failed to close remote directory. + + + + + Failed to open remote file for reading. + + + + + Failed to retrieve information on the remote file ('stat' failed). + + + + + Failed to read remote file. + + + + + + Failed to close remote file. + + + + + Failed to open remote file for writing. + + + + + Failed to write remote file. + + + + + Cannot append to remote file: Server does not support the file size attribute. + + + + + SFTP channel closed unexpectedly. + + + + + Server could not start session: %1 + + + + + Error reading local file: %1 + + + + + QSsh::Internal::SshChannelManager + + + Unexpected request success packet. + + + + + Unexpected request failure packet. + + + + + Invalid channel id %1 + + + + + QSsh::Internal::SshConnectionPrivate + + + SSH Protocol error: %1 + + + + + Botan library exception: %1 + + + + + Server identification string is %n characters long, but the maximum allowed length is 255. + + + + + + + + + Server identification string contains illegal NUL character. + + + + + Server Identification string "%1" is invalid. + + + + + Server protocol version is "%1", but needs to be 2.0 or 1.99. + + + + + Server identification string is invalid (missing carriage return). + + + + + Server reports protocol version 1.99, but sends data before the identification string, which is not allowed. + + + + + + + + Unexpected packet of type %1. + + + + + Password expired. + + + + + Server rejected key. + + + + + Server rejected password. + + + + + The server sent an unexpected SSH packet of type SSH_MSG_UNIMPLEMENTED. + + + + + Server closed connection: %1 + + + + + Connection closed unexpectedly. + + + + + Timeout waiting for reply from server. + + + + + No private key file given. + + + + + Private key file error: %1 + + + + + QSsh::Internal::SshRemoteProcessPrivate + + + Process killed by signal + + + + + Server sent invalid signal "%1" + + + + + QSsh::SftpFileSystemModel + + + File Type + + + + + File Name + + + + + Error getting "stat" info about "%1": %2 + + + + + Error listing contents of directory "%1": %2 + + + + + QSsh::Ssh + + + Failed to open key file "%1" for reading: %2 + + + + + Failed to open key file "%1" for writing: %2 + + + + + Password Required + + + + + Please enter the password for your private key. + + + + + QSsh::SshKeyCreationDialog + + + SSH Key Configuration + + + + + Options + + + + + Key algorithm: + + + + + &RSA + + + + + &DSA + + + + + ECDSA + + + + + Key &size: + + + + + Private key file: + + + + + + Browse... + + + + + Public key file: + + + + + &Generate And Save Key Pair + + + + + &Cancel + + + + + Choose... + + + + + Key Generation Failed + + + + + Choose Private Key File Name + + + + + Cannot Save Key File + + + + + Failed to create directory: "%1". + + + + + Cannot Save Private Key File + + + + + The private key file could not be saved: %1 + + + + + Cannot Save Public Key File + + + + + The public key file could not be saved: %1 + + + + + File Exists + + + + + There already is a file of that name. Do you want to overwrite it? + + + + + SshConnection + + + Server and client capabilities don't match. Client list was: %1. +Server list was %2. + + + + + SshKeyGenerator + + + Error generating key: %1 + + + + + Password for Private Key + + + + + It is recommended that you secure your private key +with a password, which you can enter below. + + + + + Encrypt Key File + + + + + Do Not Encrypt Key File + + + + + VpnConnection + + + Mbps + + + + diff --git a/client/ui/Controls/SlidingStackedWidget.cpp b/client/ui/Controls/SlidingStackedWidget.cpp new file mode 100644 index 00000000..104de522 --- /dev/null +++ b/client/ui/Controls/SlidingStackedWidget.cpp @@ -0,0 +1,193 @@ +#include "SlidingStackedWidget.h" + +SlidingStackedWidget::SlidingStackedWidget(QWidget *parent) + : QStackedWidget(parent) +{ + if (parent != 0) { + m_mainwindow = parent; + } + else { + m_mainwindow = this; + qDebug().noquote() << "ATTENTION: untested mainwindow case !"; + } + // parent should not be 0; not tested for any other case yet !! + +#ifdef Q_OS_SYMBIAN +#ifndef __S60_50__ + qDebug().noquote() << "WARNING: ONLY TESTED AND 5TH EDITION"; +#endif // __S60_50__ +#endif // Q_OS_SYMBIAN + + // Now, initialize some private variables with default values + m_vertical = false; + // setVerticalMode(true); + m_speed = 500; + m_animationtype = QEasingCurve::OutBack; // check out the QEasingCurve documentation for different styles + m_now = 0; + m_next = 0; + m_wrap = false; + m_pnow = QPoint(0,0); + m_active = false; +} + +SlidingStackedWidget::~SlidingStackedWidget() { +} + +void SlidingStackedWidget::setVerticalMode(bool vertical) { + m_vertical = vertical; +} + +void SlidingStackedWidget::setSpeed(int speed) { + m_speed = speed; +} + +void SlidingStackedWidget::setAnimation(enum QEasingCurve::Type animationtype) { + m_animationtype = animationtype; +} + +void SlidingStackedWidget::setWrap(bool wrap) { + m_wrap = wrap; +} + +void SlidingStackedWidget::slideInNext() { + int now = currentIndex(); + if (m_wrap || (now < count() - 1)) + // count is inherit from QStackedWidget + slideInIdx(now + 1); +} + +void SlidingStackedWidget::slideInPrev() { + int now = currentIndex(); + if (m_wrap || (now > 0)) + slideInIdx(now - 1); +} + +void SlidingStackedWidget::slideInIdx(int idx, enum t_direction direction) { + // int idx, t_direction direction=AUTOMATIC + if (idx > count() - 1) { + direction = m_vertical ? TOP2BOTTOM : RIGHT2LEFT; + idx = (idx) % count(); + } + else if (idx < 0) { + direction = m_vertical ? BOTTOM2TOP: LEFT2RIGHT; + idx = (idx + count()) % count(); + } + slideInWgtImpl(widget(idx), direction); + // widget() is a function inherited from QStackedWidget +} + +void SlidingStackedWidget::slideInWidget(QWidget *widget, SlidingStackedWidget::t_direction direction) +{ + Q_UNUSED(direction); + +#ifdef Q_OS_WIN + int idx = indexOf(widget); + slideInIdx(idx, direction); +#endif + +#ifdef Q_OS_MAC + setCurrentWidget(widget); +#endif +} + +void SlidingStackedWidget::slideInWgtImpl(QWidget * newwidget, enum t_direction direction) { + if (m_active) { + return; + } + else m_active = true; + + enum t_direction directionhint; + int now = currentIndex(); // currentIndex() is a function inherited from QStackedWidget + int next = indexOf(newwidget); + if (now == next) { + m_active = false; + return; + } + else if (now < next) { + directionhint = m_vertical ? TOP2BOTTOM : RIGHT2LEFT; + } + else { + directionhint = m_vertical ? BOTTOM2TOP : LEFT2RIGHT; + } + if (direction == AUTOMATIC) { + direction = directionhint; + } + // NOW.... + // calculate the shifts + + int offsetx = frameRect().width(); // inherited from mother + int offsety = frameRect().height(); // inherited from mother + + // the following is important, to ensure that the new widget + // has correct geometry information when sliding in first time + widget(next)->setGeometry(0, 0, offsetx, offsety); + + if (direction == BOTTOM2TOP) { + offsetx = 0; + offsety = -offsety; + } + else if (direction == TOP2BOTTOM) { + offsetx = 0; + // offsety = offsety; + } + else if (direction == RIGHT2LEFT) { + offsetx = -offsetx; + offsety = 0; + } + else if (direction == LEFT2RIGHT) { + // offsetx = offsetx; + offsety = 0; + } + // re-position the next widget outside/aside of the display area + QPoint pnext = widget(next)->pos(); + QPoint pnow = widget(now)->pos(); + m_pnow = pnow; + + widget(next)->move(pnext.x() - offsetx, pnext.y() - offsety); + // make it visible/show + widget(next)->show(); + widget(next)->raise(); + + // animate both, the now and next widget to the side, using animation framework + QPropertyAnimation *animnow = new QPropertyAnimation(widget(now), "pos"); + + animnow->setDuration(m_speed); + animnow->setEasingCurve(m_animationtype); + animnow->setStartValue(QPoint(pnow.x(), pnow.y())); + animnow->setEndValue(QPoint(offsetx + pnow.x(), offsety + pnow.y())); + QPropertyAnimation *animnext = new QPropertyAnimation(widget(next), "pos"); + animnext->setDuration(m_speed); + animnext->setEasingCurve(m_animationtype); + animnext->setStartValue(QPoint(-offsetx + pnext.x(), offsety + pnext.y())); + animnext->setEndValue(QPoint(pnext.x(), pnext.y())); + + QParallelAnimationGroup *animgroup = new QParallelAnimationGroup; + + animgroup->addAnimation(animnow); + animgroup->addAnimation(animnext); + + QObject::connect(animgroup, SIGNAL(finished()),this,SLOT(animationDoneSlot())); + m_next = next; + m_now = now; + m_active = true; + animgroup->start(); + + // note; the rest is done via a connect from the animation ready; + // animation->finished() provides a signal when animation is done; + // so we connect this to some post processing slot, + // that we implement here below in animationDoneSlot. +} + +void SlidingStackedWidget::animationDoneSlot(void) { + // when ready, call the QStackedWidget slot setCurrentIndex(int) + setCurrentIndex(m_next); // this function is inherited from QStackedWidget + // then hide the outshifted widget now, and (may be done already implicitely by QStackedWidget) + widget(m_now)->hide(); + // then set the position of the outshifted widget now back to its original + widget(m_now)->move(m_pnow); + // so that the application could also still call the QStackedWidget original functions/slots for changings + // widget(m_now)->update(); + // setCurrentIndex(m_next); // this function is inherit from QStackedWidget + m_active = false; + emit animationFinished(); +} diff --git a/client/ui/Controls/SlidingStackedWidget.h b/client/ui/Controls/SlidingStackedWidget.h new file mode 100644 index 00000000..979e8f6a --- /dev/null +++ b/client/ui/Controls/SlidingStackedWidget.h @@ -0,0 +1,76 @@ +#ifndef SLIDINGSTACKEDWIDGET_H +#define SLIDINGSTACKEDWIDGET_H + +#include + +#include +#include +#include +#include +#include + +/* Description + + SlidingStackedWidget is a class that is derived from QtStackedWidget + and allows smooth side shifting of widgets, in addition + to the original hard switching from one to another as offered by + QStackedWidget itself. +*/ + +class SlidingStackedWidget : public QStackedWidget { + Q_OBJECT + +public: + // This enumeration is used to define the animation direction + enum t_direction { + LEFT2RIGHT, + RIGHT2LEFT, + TOP2BOTTOM, + BOTTOM2TOP, + AUTOMATIC + }; + + // The Constructor and Destructor + SlidingStackedWidget(QWidget *parent); + ~SlidingStackedWidget(void); + +public slots: + // Some basic settings API + void setSpeed(int speed); // animation duration in milliseconds + void setAnimation(enum QEasingCurve::Type animationtype); // check out the QEasingCurve documentation for different styles + void setVerticalMode(bool vertical=true); + void setWrap(bool wrap); // wrapping is related to slideInNext/Prev;it defines the behaviour when reaching last/first page + + // The Animation / Page Change API + void slideInNext(); + void slideInPrev(); + void slideInIdx(int idx, enum t_direction direction = AUTOMATIC); + void slideInWidget(QWidget *widget, enum t_direction direction = AUTOMATIC); + +signals: + // this is used for internal purposes in the class engine + void animationFinished(void); + +protected slots: + // this is used for internal purposes in the class engine + void animationDoneSlot(void); + +protected: + // this is used for internal purposes in the class engine + void slideInWgtImpl(QWidget *widget, enum t_direction direction = AUTOMATIC); + + QWidget *m_mainwindow; + + int m_speed; + enum QEasingCurve::Type m_animationtype; + bool m_vertical; + int m_now; + int m_next; + bool m_wrap; + QPoint m_pnow; + bool m_active; + + QList blockedPageList; +}; + +#endif // SLIDINGSTACKEDWIDGET_H diff --git a/client/ui/framelesswindow.cpp b/client/ui/framelesswindow.cpp new file mode 100644 index 00000000..612f2e01 --- /dev/null +++ b/client/ui/framelesswindow.cpp @@ -0,0 +1,306 @@ +// This code is a part of Qt-Nice-Frameless-Window +// https://github.com/Bringer-of-Light/Qt-Nice-Frameless-Window +// Licensed by MIT License - https://github.com/Bringer-of-Light/Qt-Nice-Frameless-Window/blob/master/LICENSE + + +#include "framelesswindow.h" +#include +#include +#include +#ifdef Q_OS_WIN + +#include +#include +#include +#include +#include // Fixes error C2504: 'IUnknown' : base class undefined +#include +#include +#pragma comment (lib,"Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved external symbol __imp__DwmExtendFrameIntoClientArea +#pragma comment (lib,"user32.lib") + +CFramelessWindow::CFramelessWindow(QWidget *parent) + : QMainWindow(parent), + m_titlebar(Q_NULLPTR), + m_borderWidth(5), + m_bJustMaximized(false), + m_bResizeable(true) +{ +// setWindowFlag(Qt::Window,true); +// setWindowFlag(Qt::FramelessWindowHint, true); +// setWindowFlag(Qt::WindowSystemMenuHint, true); +// setWindowFlag() is not avaliable before Qt v5.9, so we should use setWindowFlags instead + + setWindowFlags(windowFlags() | Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + + setResizeable(m_bResizeable); +} + +void CFramelessWindow::setResizeable(bool resizeable) +{ + bool visible = isVisible(); + m_bResizeable = resizeable; + if (m_bResizeable){ + setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint); +// setWindowFlag(Qt::WindowMaximizeButtonHint); + + //此行代码可以带回Aero效果,同时也带回了标题栏和边框,在nativeEvent()会再次去掉标题栏 + // + //this line will get titlebar/thick frame/Aero back, which is exactly what we want + //we will get rid of titlebar and thick frame again in nativeEvent() later + HWND hwnd = (HWND)this->winId(); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); + }else{ + setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint); +// setWindowFlag(Qt::WindowMaximizeButtonHint,false); + + HWND hwnd = (HWND)this->winId(); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX & ~WS_CAPTION); + } + + //保留一个像素的边框宽度,否则系统不会绘制边框阴影 + // + //we better left 1 piexl width of border untouch, so OS can draw nice shadow around it + const MARGINS shadow = { 1, 1, 1, 1 }; + DwmExtendFrameIntoClientArea(HWND(winId()), &shadow); + + setVisible(visible); +} + +void CFramelessWindow::setResizeableAreaWidth(int width) +{ + if (1 > width) width = 1; + m_borderWidth = width; +} + +void CFramelessWindow::setTitleBar(QWidget* titlebar) +{ + m_titlebar = titlebar; + if (!titlebar) return; + connect(titlebar, SIGNAL(destroyed(QObject*)), this, SLOT(onTitleBarDestroyed())); +} + +void CFramelessWindow::onTitleBarDestroyed() +{ + if (m_titlebar == QObject::sender()) + { + m_titlebar = Q_NULLPTR; + } +} + +void CFramelessWindow::addIgnoreWidget(QWidget* widget) +{ + if (!widget) return; + if (m_whiteList.contains(widget)) return; + m_whiteList.append(widget); +} + +bool CFramelessWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) +{ + //Workaround for known bug -> check Qt forum : https://forum.qt.io/topic/93141/qtablewidget-itemselectionchanged/13 + #if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1)) + MSG* msg = *reinterpret_cast(message); + #else + MSG* msg = reinterpret_cast(message); + #endif + + switch (msg->message) + { + case WM_NCCALCSIZE: + { + NCCALCSIZE_PARAMS& params = *reinterpret_cast(msg->lParam); + if (params.rgrc[0].top != 0) + params.rgrc[0].top -= 1; + + //this kills the window frame and title bar we added with WS_THICKFRAME and WS_CAPTION + *result = WVR_REDRAW; + return true; + } + case WM_NCHITTEST: + { + *result = 0; + + const LONG border_width = m_borderWidth; + RECT winrect; + GetWindowRect(HWND(winId()), &winrect); + + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + + if(m_bResizeable) + { + + bool resizeWidth = minimumWidth() != maximumWidth(); + bool resizeHeight = minimumHeight() != maximumHeight(); + + if(resizeWidth) + { + //left border + if (x >= winrect.left && x < winrect.left + border_width) + { + *result = HTLEFT; + } + //right border + if (x < winrect.right && x >= winrect.right - border_width) + { + *result = HTRIGHT; + } + } + if(resizeHeight) + { + //bottom border + if (y < winrect.bottom && y >= winrect.bottom - border_width) + { + *result = HTBOTTOM; + } + //top border + if (y >= winrect.top && y < winrect.top + border_width) + { + *result = HTTOP; + } + } + if(resizeWidth && resizeHeight) + { + //bottom left corner + if (x >= winrect.left && x < winrect.left + border_width && + y < winrect.bottom && y >= winrect.bottom - border_width) + { + *result = HTBOTTOMLEFT; + } + //bottom right corner + if (x < winrect.right && x >= winrect.right - border_width && + y < winrect.bottom && y >= winrect.bottom - border_width) + { + *result = HTBOTTOMRIGHT; + } + //top left corner + if (x >= winrect.left && x < winrect.left + border_width && + y >= winrect.top && y < winrect.top + border_width) + { + *result = HTTOPLEFT; + } + //top right corner + if (x < winrect.right && x >= winrect.right - border_width && + y >= winrect.top && y < winrect.top + border_width) + { + *result = HTTOPRIGHT; + } + } + } + if (0!=*result) return true; + + //*result still equals 0, that means the cursor locate OUTSIDE the frame area + //but it may locate in titlebar area + if (!m_titlebar) return false; + + //support highdpi + double dpr = this->devicePixelRatioF(); + QPoint pos = m_titlebar->mapFromGlobal(QPoint(x/dpr,y/dpr)); + + if (!m_titlebar->rect().contains(pos)) return false; + QWidget* child = m_titlebar->childAt(pos); + if (!child) + { + *result = HTCAPTION; + return true; + }else{ + if (m_whiteList.contains(child)) + { + *result = HTCAPTION; + return true; + } + } + return false; + } //end case WM_NCHITTEST + case WM_GETMINMAXINFO: + { + if (::IsZoomed(msg->hwnd)) { + RECT frame = { 0, 0, 0, 0 }; + AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0); + + //record frame area data + double dpr = this->devicePixelRatioF(); + + m_frames.setLeft(abs(frame.left)/dpr+0.5); + m_frames.setTop(abs(frame.bottom)/dpr+0.5); + m_frames.setRight(abs(frame.right)/dpr+0.5); + m_frames.setBottom(abs(frame.bottom)/dpr+0.5); + + QMainWindow::setContentsMargins(m_frames.left()+m_margins.left(), \ + m_frames.top()+m_margins.top(), \ + m_frames.right()+m_margins.right(), \ + m_frames.bottom()+m_margins.bottom()); + m_bJustMaximized = true; + }else { + if (m_bJustMaximized) + { + QMainWindow::setContentsMargins(m_margins); + m_frames = QMargins(); + m_bJustMaximized = false; + } + } + return false; + } + default: + return QMainWindow::nativeEvent(eventType, message, result); + } +} + +void CFramelessWindow::setContentsMargins(const QMargins &margins) +{ + QMainWindow::setContentsMargins(margins+m_frames); + m_margins = margins; +} +void CFramelessWindow::setContentsMargins(int left, int top, int right, int bottom) +{ + QMainWindow::setContentsMargins(left+m_frames.left(),\ + top+m_frames.top(), \ + right+m_frames.right(), \ + bottom+m_frames.bottom()); + m_margins.setLeft(left); + m_margins.setTop(top); + m_margins.setRight(right); + m_margins.setBottom(bottom); +} +QMargins CFramelessWindow::contentsMargins() const +{ + QMargins margins = QMainWindow::contentsMargins(); + margins -= m_frames; + return margins; +} +void CFramelessWindow::getContentsMargins(int *left, int *top, int *right, int *bottom) const +{ + QMainWindow::getContentsMargins(left,top,right,bottom); + if (!(left&&top&&right&&bottom)) return; + if (isMaximized()) + { + *left -= m_frames.left(); + *top -= m_frames.top(); + *right -= m_frames.right(); + *bottom -= m_frames.bottom(); + } +} +QRect CFramelessWindow::contentsRect() const +{ + QRect rect = QMainWindow::contentsRect(); + int width = rect.width(); + int height = rect.height(); + rect.setLeft(rect.left() - m_frames.left()); + rect.setTop(rect.top() - m_frames.top()); + rect.setWidth(width); + rect.setHeight(height); + return rect; +} +void CFramelessWindow::showFullScreen() +{ + if (isMaximized()) + { + QMainWindow::setContentsMargins(m_margins); + m_frames = QMargins(); + } + QMainWindow::showFullScreen(); +} + +#endif //Q_OS_WIN diff --git a/client/ui/framelesswindow.h b/client/ui/framelesswindow.h new file mode 100644 index 00000000..ca8a69f6 --- /dev/null +++ b/client/ui/framelesswindow.h @@ -0,0 +1,158 @@ +// This code is a part of Qt-Nice-Frameless-Window +// https://github.com/Bringer-of-Light/Qt-Nice-Frameless-Window +// Licensed by MIT License - https://github.com/Bringer-of-Light/Qt-Nice-Frameless-Window/blob/master/LICENSE + + +#ifndef CFRAMELESSWINDOW_H +#define CFRAMELESSWINDOW_H +#include "qsystemdetection.h" +#include +#include + +//A nice frameless window for both Windows and OS X +//Author: Bringer-of-Light +//Github: https://github.com/Bringer-of-Light/Qt-Nice-Frameless-Window +// Usage: use "CFramelessWindow" as base class instead of "QMainWindow", and enjoy +#ifdef Q_OS_WIN +#include +#include +#include +#include +class CFramelessWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit CFramelessWindow(QWidget *parent = 0); +public: + + //设置是否可以通过鼠标调整窗口大小 + //if resizeable is set to false, then the window can not be resized by mouse + //but still can be resized programtically + void setResizeable(bool resizeable=true); + bool isResizeable(){return m_bResizeable;} + + //设置可调整大小区域的宽度,在此区域内,可以使用鼠标调整窗口大小 + //set border width, inside this aera, window can be resized by mouse + void setResizeableAreaWidth(int width = 5); +protected: + //设置一个标题栏widget,此widget会被当做标题栏对待 + //set a widget which will be treat as SYSTEM titlebar + void setTitleBar(QWidget* titlebar); + + //在标题栏控件内,也可以有子控件如标签控件“label1”,此label1遮盖了标题栏,导致不能通过label1拖动窗口 + //要解决此问题,使用addIgnoreWidget(label1) + //generally, we can add widget say "label1" on titlebar, and it will cover the titlebar under it + //as a result, we can not drag and move the MainWindow with this "label1" again + //we can fix this by add "label1" to a ignorelist, just call addIgnoreWidget(label1) + void addIgnoreWidget(QWidget* widget); + + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +private slots: + void onTitleBarDestroyed(); +public: + void setContentsMargins(const QMargins &margins); + void setContentsMargins(int left, int top, int right, int bottom); + QMargins contentsMargins() const; + QRect contentsRect() const; + void getContentsMargins(int *left, int *top, int *right, int *bottom) const; +public slots: + void showFullScreen(); +private: + QWidget* m_titlebar; + QList m_whiteList; + int m_borderWidth; + + QMargins m_margins; + QMargins m_frames; + bool m_bJustMaximized; + + bool m_bResizeable; +}; + +#elif defined Q_OS_MAC +#include +#include +#include +class CFramelessWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit CFramelessWindow(QWidget *parent = 0); +private: + void initUI(); +public: + //设置可拖动区域的高度,在此区域内,可以通过鼠标拖动窗口, 0表示整个窗口都可拖动 + //In draggable area, window can be moved by mouse, (height = 0) means that the whole window is draggable + void setDraggableAreaHeight(int height = 0); + + //只有OS X10.10及以后系统,才支持OS X原生样式包括:三个系统按钮、窗口圆角、窗口阴影 + //类初始化完成后,可以通过此函数查看是否已经启用了原生样式。如果未启动,需要自定义关闭按钮、最小化按钮、最大化按钮 + //Native style(three system button/ round corner/ drop shadow) works only on OS X 10.10 or later + //after init, we should check whether NativeStyle is OK with this function + //if NOT ok, we should implement close button/ min button/ max button ourself + bool isNativeStyleOK() {return m_bNativeSystemBtn;} + + //如果设置setCloseBtnQuit(false),那么点击关闭按钮后,程序不会退出,而是会隐藏,只有在OS X 10.10 及以后系统中有效 + //if setCloseBtnQuit(false), then when close button is clicked, the application will hide itself instead of quit + //be carefull, after you set this to false, you can NOT change it to true again + //this function should be called inside of the constructor function of derived classes, and can NOT be called more than once + //only works for OS X 10.10 or later + void setCloseBtnQuit(bool bQuit = true); + + //启用或禁用关闭按钮,只有在isNativeStyleOK()返回true的情况下才有效 + //enable or disable Close button, only worked if isNativeStyleOK() returns true + void setCloseBtnEnabled(bool bEnable = true); + + //启用或禁用最小化按钮,只有在isNativeStyleOK()返回true的情况下才有效 + //enable or disable Miniaturize button, only worked if isNativeStyleOK() returns true + void setMinBtnEnabled(bool bEnable = true); + + //启用或禁用zoom(最大化)按钮,只有在isNativeStyleOK()返回true的情况下才有效 + //enable or disable Zoom button(fullscreen button), only worked if isNativeStyleOK() returns true + void setZoomBtnEnabled(bool bEnable = true); + + bool isCloseBtnEnabled() {return m_bIsCloseBtnEnabled;} + bool isMinBtnEnabled() {return m_bIsMinBtnEnabled;} + bool isZoomBtnEnabled() {return m_bIsZoomBtnEnabled;} +protected: + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); +private: + int m_draggableHeight; + bool m_bWinMoving; + bool m_bMousePressed; + QPoint m_MousePos; + QPoint m_WindowPos; + bool m_bCloseBtnQuit; + bool m_bNativeSystemBtn; + bool m_bIsCloseBtnEnabled, m_bIsMinBtnEnabled, m_bIsZoomBtnEnabled; + + //=============================================== + //TODO + //下面的代码是试验性质的 + //tentative code + + //窗口从全屏状态恢复正常大小时,标题栏又会出现,原因未知。 + //默认情况下,系统的最大化按钮(zoom button)是进入全屏,为了避免标题栏重新出现的问题, + //以上代码已经重新定义了系统zoom button的行为,是其功能变为最大化而不是全屏 + //以下代码尝试,每次窗口从全屏状态恢复正常大小时,都再次进行设置,以消除标题栏 + //after the window restore from fullscreen mode, the titlebar will show again, it looks like a BUG + //on OS X 10.10 and later, click the system green button (zoom button) will make the app become fullscreen + //so we have override it's action to "maximized" in the CFramelessWindow Constructor function + //but we may try something else such as delete the titlebar again and again... +private: + bool m_bTitleBarVisible; + + void setTitlebarVisible(bool bTitlebarVisible = false); + bool isTitlebarVisible() {return m_bTitleBarVisible;} +private slots: + void onRestoreFromFullScreen(); +signals: + void restoreFromFullScreen(); +protected: + void resizeEvent(QResizeEvent *event); +}; +#endif + +#endif // CFRAMELESSWINDOW_H diff --git a/client/ui/macos_util.h b/client/ui/macos_util.h new file mode 100644 index 00000000..831f1f88 --- /dev/null +++ b/client/ui/macos_util.h @@ -0,0 +1,8 @@ +#ifndef OSXUTIL_H +#define OSXUTIL_H +#include +#include + +void fixWidget(QWidget *widget); + +#endif diff --git a/client/ui/macos_util.mm b/client/ui/macos_util.mm new file mode 100644 index 00000000..9f433747 --- /dev/null +++ b/client/ui/macos_util.mm @@ -0,0 +1,48 @@ +#include +#include +#include "macos_util.h" + +//this Objective-c class is used to override the action of system close button and zoom button +//https://stackoverflow.com/questions/27643659/setting-c-function-as-selector-for-nsbutton-produces-no-results +@interface ButtonPasser : NSObject{ +} +@property(readwrite) QMainWindow* window; ++ (void)closeButtonAction:(id)sender; +- (void)zoomButtonAction:(id)sender; +@end + +@implementation ButtonPasser{ +} ++ (void)closeButtonAction:(id)sender +{ + Q_UNUSED(sender); + ProcessSerialNumber pn; + GetFrontProcess (&pn); + ShowHideProcess(&pn,false); +} +- (void)zoomButtonAction:(id)sender +{ + Q_UNUSED(sender); + if (0 == self.window) return; + if (self.window->isMaximized()) self.window->showNormal(); + else self.window->showMaximized(); +} +@end + +void fixWidget(QWidget *widget) +{ + NSView *view = (NSView *)widget->winId(); + if (0 == view) return; + NSWindow *window = view.window; + if (0 == window) return; + + //override the action of close button + //https://stackoverflow.com/questions/27643659/setting-c-function-as-selector-for-nsbutton-produces-no-results + //https://developer.apple.com/library/content/documentation/General/Conceptual/CocoaEncyclopedia/Target-Action/Target-Action.html +// NSButton *closeButton = [window standardWindowButton:NSWindowCloseButton]; +// [closeButton setTarget:[ButtonPasser class]]; +// [closeButton setAction:@selector(closeButtonAction:)]; + + [[window standardWindowButton:NSWindowZoomButton] setHidden:YES]; + [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; +} diff --git a/client/ui/mainwindow.cpp b/client/ui/mainwindow.cpp new file mode 100644 index 00000000..9a17e3af --- /dev/null +++ b/client/ui/mainwindow.cpp @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include + +#include "communicator.h" + +#include "core/errorstrings.h" +#include "core/openvpnconfigurator.h" +#include "core/servercontroller.h" + +#include "debug.h" +#include "defines.h" +#include "mainwindow.h" +#include "settings.h" +#include "ui_mainwindow.h" +#include "utils.h" +#include "vpnconnection.h" + +#ifdef Q_OS_MAC +#include "ui/macos_util.h" +#endif + +MainWindow::MainWindow(QWidget *parent) : +#ifdef Q_OS_WIN + CFramelessWindow(parent), +#else + QMainWindow(parent), +#endif + ui(new Ui::MainWindow), + m_settings(new Settings), + m_vpnConnection(nullptr) +{ + ui->setupUi(this); + ui->widget_tittlebar->installEventFilter(this); + + ui->stackedWidget_main->setSpeed(200); + ui->stackedWidget_main->setAnimation(QEasingCurve::Linear); + + ui->label_new_server_wait_info->setVisible(false); + ui->progressBar_new_server_connection->setMinimum(0); + ui->progressBar_new_server_connection->setMaximum(300); + +#ifdef Q_OS_MAC + ui->widget_tittlebar->hide(); + ui->stackedWidget_main->move(0,0); + fixWidget(this); +#endif + + // Post initialization + + if (m_settings->haveAuthData()) { + goToPage(Page::Vpn); + } else { + goToPage(Page::Initialization); + } + + //goToPage(Page::Initialization); + + connect(ui->pushButton_blocked_list, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBlockedListClicked(bool))); + connect(ui->pushButton_connect, SIGNAL(toggled(bool)), this, SLOT(onPushButtonConnectToggled(bool))); + connect(ui->pushButton_settings, SIGNAL(clicked(bool)), this, SLOT(onPushButtonSettingsClicked(bool))); + + connect(ui->pushButton_back_from_sites, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBackFromSitesClicked(bool))); + connect(ui->pushButton_back_from_settings, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBackFromSettingsClicked(bool))); + connect(ui->pushButton_new_server_setup, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerSetup(bool))); + connect(ui->pushButton_back_from_new_server, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBackFromNewServerClicked(bool))); + connect(ui->pushButton_new_server_connect_with_new_data, SIGNAL(clicked(bool)), this, SLOT(onPushButtonNewServerConnectWithNewData(bool))); + + setFixedSize(width(),height()); + + qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME).arg(APP_VERSION); + qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()); + + Utils::initializePath(Utils::configPath()); + + m_vpnConnection = new VpnConnection(this); + connect(m_vpnConnection, SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); + connect(m_vpnConnection, SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState))); + + onConnectionStateChanged(VpnProtocol::ConnectionState::Disconnected); + + qDebug().noquote() << QString("Default config: %1").arg(Utils::defaultVpnConfigFileName()); +} + +MainWindow::~MainWindow() +{ + hide(); + + m_vpnConnection->disconnectFromVpn(); + for (int i = 0; i < 50; i++) { + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + QThread::msleep(100); + if (m_vpnConnection->disconnected()) { + break; + } + } + + delete m_vpnConnection; + delete ui; + + qDebug() << "Application closed"; +} + +void MainWindow::goToPage(Page page) +{ + ui->stackedWidget_main->slideInIdx(static_cast(page)); +} + +bool MainWindow::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->widget_tittlebar) { + QMouseEvent *mouseEvent = static_cast(event); + + if (!mouseEvent) + return false; + + if(event->type() == QEvent::MouseButtonPress) { + offset = mouseEvent->pos(); + canMove = true; + } + + if(event->type() == QEvent::MouseButtonRelease) { + canMove = false; + } + + if (event->type() == QEvent::MouseMove) { + if(canMove && (mouseEvent->buttons() & Qt::LeftButton)) { + move(mapToParent(mouseEvent->pos() - offset)); + } + + event->ignore(); + return false; + } + } + + return QMainWindow::eventFilter(obj, event); +} + +void MainWindow::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_L: + if (!Debug::openLogsFolder()) { + QMessageBox::warning(this, APPLICATION_NAME, tr("Cannot open logs folder!")); + } + break; + default: + ; + } +} + +void MainWindow::onPushButtonNewServerConnectWithNewData(bool clicked) +{ + if (ui->lineEdit_new_server_ip->text().isEmpty() || + ui->lineEdit_new_server_login->text().isEmpty() || + ui->lineEdit_new_server_password->text().isEmpty() ) { + QMessageBox::warning(this, APPLICATION_NAME, tr("Please fill in all fields")); + return; + } + + qDebug() << "Start connection with new data"; + + ServerCredentials serverCredentials; + serverCredentials.hostName = ui->lineEdit_new_server_ip->text(); + if (serverCredentials.hostName.contains(":")) { + serverCredentials.port = serverCredentials.hostName.split(":").at(1).toInt(); + serverCredentials.hostName = serverCredentials.hostName.split(":").at(0); + } + serverCredentials.userName = ui->lineEdit_new_server_login->text(); + serverCredentials.password = ui->lineEdit_new_server_password->text(); + + m_settings->setServerCredentials(serverCredentials); + m_settings->save(); + + ui->page_new_server->setEnabled(false); + ui->pushButton_new_server_connect_with_new_data->setVisible(false); + ui->label_new_server_wait_info->setVisible(true); + + QTimer timer; + connect(&timer, &QTimer::timeout, [&](){ + ui->progressBar_new_server_connection->setValue(ui->progressBar_new_server_connection->value() + 1); + }); + + ui->progressBar_new_server_connection->setValue(0); + timer.start(1000); + + + ErrorCode e = ServerController::setupServer(serverCredentials, Protocol::Any); + if (e) { + ui->page_new_server->setEnabled(true); + ui->pushButton_new_server_connect_with_new_data->setVisible(true); + ui->label_new_server_wait_info->setVisible(false); + + QMessageBox::warning(this, APPLICATION_NAME, + tr("Error occurred while configuring server.") + "\n" + + errorString(e) + "\n" + + tr("See logs for details.")); + + return; + } + + // just ui progressbar tweak + timer.stop(); + + int remaining_val = ui->progressBar_new_server_connection->maximum() - ui->progressBar_new_server_connection->value(); + + if (remaining_val > 0) { + QTimer timer1; + QEventLoop loop1; + + connect(&timer1, &QTimer::timeout, [&](){ + ui->progressBar_new_server_connection->setValue(ui->progressBar_new_server_connection->value() + 1); + if (ui->progressBar_new_server_connection->value() >= ui->progressBar_new_server_connection->maximum()) { + loop1.quit(); + } + }); + + timer1.start(5); + loop1.exec(); + } + + goToPage(Page::Vpn); + ui->pushButton_connect->setChecked(true); +} + +void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData) +{ + ui->label_speed_received->setText(VpnConnection::bytesToText(receivedData)); + ui->label_speed_sent->setText(VpnConnection::bytesToText(sentData)); +} + +void MainWindow::onPushButtonBackFromNewServerClicked(bool) +{ + goToPage(Page::Initialization); +} + +void MainWindow::onPushButtonNewServerSetup(bool) +{ + goToPage(Page::NewServer); +} + +void MainWindow::onPushButtonBackFromSettingsClicked(bool) +{ + goToPage(Page::Vpn); +} + +void MainWindow::onPushButtonBackFromSitesClicked(bool) +{ + goToPage(Page::Vpn); +} + +void MainWindow::onPushButtonBlockedListClicked(bool) +{ + goToPage(Page::Sites); +} + +void MainWindow::onPushButtonSettingsClicked(bool) +{ + goToPage(Page::SomeSettings); +} + +void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state) +{ + bool pushButtonConnectEnabled = false; + ui->label_state->setText(VpnProtocol::textConnectionState(state)); + + switch (state) { + case VpnProtocol::ConnectionState::Disconnected: + onBytesChanged(0,0); + ui->pushButton_connect->setChecked(false); + pushButtonConnectEnabled = true; + break; + case VpnProtocol::ConnectionState::Preparing: + pushButtonConnectEnabled = false; + break; + case VpnProtocol::ConnectionState::Connecting: + pushButtonConnectEnabled = false; + break; + case VpnProtocol::ConnectionState::Connected: + pushButtonConnectEnabled = true; + break; + case VpnProtocol::ConnectionState::Disconnecting: + pushButtonConnectEnabled = false; + break; + case VpnProtocol::ConnectionState::TunnelReconnecting: + pushButtonConnectEnabled = false; + break; + case VpnProtocol::ConnectionState::Error: + pushButtonConnectEnabled = true; + break; + case VpnProtocol::ConnectionState::Unknown: + default: + pushButtonConnectEnabled = true; + ; + } + + ui->pushButton_connect->setEnabled(pushButtonConnectEnabled); +} + +void MainWindow::onPushButtonConnectToggled(bool checked) +{ + if (checked) { + // TODO: Call connectToVpn with restricted server account + ServerCredentials credentials = m_settings->serverCredentials(); + + ErrorCode errorCode = m_vpnConnection->connectToVpn(credentials); + if (errorCode) { + ui->pushButton_connect->setChecked(false); + QMessageBox::critical(this, APPLICATION_NAME, errorString(errorCode)); + return; + } + ui->pushButton_connect->setEnabled(false); + } else { + m_vpnConnection->disconnectFromVpn(); + } +} + +void MainWindow::on_pushButton_close_clicked() +{ + qApp->exit(); +} diff --git a/client/ui/mainwindow.h b/client/ui/mainwindow.h new file mode 100644 index 00000000..6d02c862 --- /dev/null +++ b/client/ui/mainwindow.h @@ -0,0 +1,61 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include "framelesswindow.h" +#include "protocols/vpnprotocol.h" + +class Settings; +class VpnConnection; + +namespace Ui { +class MainWindow; +} + +/** + * @brief The MainWindow class - Main application window + */ +#ifdef Q_OS_WIN +class MainWindow : public CFramelessWindow +#else +class MainWindow : public QMainWindow +#endif + +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + enum class Page {Initialization = 0, NewServer = 1, Vpn = 2, Sites = 3, SomeSettings = 4, Share = 5}; + +private slots: + void onBytesChanged(quint64 receivedBytes, quint64 sentBytes); + void onConnectionStateChanged(VpnProtocol::ConnectionState state); + void onPushButtonBackFromNewServerClicked(bool clicked); + void onPushButtonBackFromSettingsClicked(bool clicked); + void onPushButtonBackFromSitesClicked(bool clicked); + void onPushButtonBlockedListClicked(bool clicked); + void onPushButtonConnectToggled(bool checked); + void onPushButtonNewServerConnectWithNewData(bool clicked); + void onPushButtonNewServerSetup(bool clicked); + void onPushButtonSettingsClicked(bool clicked); + + void on_pushButton_close_clicked(); + +private: + void goToPage(Page page); + + Ui::MainWindow *ui; + VpnConnection* m_vpnConnection; + Settings* m_settings; + + bool canMove = false; + QPoint offset; + bool eventFilter(QObject *obj, QEvent *event) override; + void keyPressEvent(QKeyEvent* event) override; +}; + +#endif // MAINWINDOW_H diff --git a/client/ui/mainwindow.ui b/client/ui/mainwindow.ui new file mode 100644 index 00000000..361a3be5 --- /dev/null +++ b/client/ui/mainwindow.ui @@ -0,0 +1,1726 @@ + + + MainWindow + + + + 0 + 0 + 380 + 670 + + + + + + + QWidget { + font: 16px "Lato"; + outline: none; + font-style: normal; + font-weight: normal; +} + +/*----------------------*/ + +QPushButton { + border: none; + color: rgb(216, 216, 216); +} +QPushButton:disabled { + border: none; + color: rgb(127, 127, 127); +} + +/*----------------------*/ + +QLabel { + color: #181922; +} +QLabel:disabled { + color: #A7A7A7; +} + +/*----------------------*/ + +QMessageBox { + background-color: #333333; +} +QMessageBox QLabel { + color: #aaa; +} + +/*----------------------*/ + +QLineEdit { + border: none; + border-bottom:2px solid rgb(120, 120, 120); + + color: rgb(140, 140, 140); + + /*font: 13pt "JMH Cthulhumbus";*/ + + background:transparent; + + selection-background-color: darkgray; +} + +QLineEdit:focus { + border-bottom:2px solid rgb(200, 200, 200); +} +QLineEdit[error] { + border-bottom:2px solid rgb(213, 40, 60); + color: rgb(213, 40, 60); +} +QLineEdit:disabled { + border-bottom:2px solid rgb(127, 127, 127); + color: rgb(127, 127, 127); +} + + +QCheckBox { + color: rgb(200, 200, 200); + + font: 63 11pt "Open Sans"; + /*font: 11pt "JMH Cthulhumbus";*/ + background: transparent; + + +} + +QCheckBox::indicator { +min-height: 20px; +min-width: 20px; + +border-image: url(:/images/controls/checkbox_unchecked.png) 0 0 0 0 stretch stretch; +} + +QCheckBox::indicator:unchecked { +border-image: url(:/images/controls/checkbox_unchecked.png) 0 0 0 0 stretch stretch; +} +QCheckBox::indicator:unchecked:hover { +border-image: url(:/images/controls/checkbox_hover.png); +} + +QCheckBox::indicator:checked { +border-image: url(:/images/controls/checkbox_checked.png); + +} + + + +QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */ + background-color: black; + opacity: 100; + width: 7px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ + margin: 0px 0px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ + +} + +QScrollBar::handle:vertical { /* The handle you scroll with */ + image-position: center; /* image is used as a small gripper in the center of the scrollbar.. You can also use background-image to use two images */ + background-color: rgb(200, 200, 200); + border-radius: 1px; + min-height: 10px; +} +QScrollBar::handle:vertical:hover { /* state when you hover over the handle */ + background-color: rgb(160, 160, 160); +} +QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */ + background-color: rgb(120, 120, 120); +} +QScrollBar::sub-line:vertical { /* button to scroll up */ + background-color: rgb(240,240,240); + height: 0px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { /* hover state of button to scroll up */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::up-arrow:vertical { /* arrow to scroll up with */ + top: 2px; +} + +QScrollBar::add-line:vertical { /* Button to scroll down */ + background-color: rgb(240,240,240); + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical:hover { /* hover state of button to scroll down */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::down-arrow:vertical { /* arrow to scroll down with */ + bottom: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: black; +} + + + + + + + + + 0 + 0 + 380 + 670 + + + + QWidget #widget_main { + background: white; +} + + + + + + 0 + 0 + 380 + 30 + + + + true + + + background: #F5F5F5; + + + + + + 330 + 10 + 16 + 16 + + + + PointingHandCursor + + + image: url(:/images/listitembg.png); +image-position: right; + + + + + + + + + + 360 + 8 + 13 + 13 + + + + PointingHandCursor + + + QPushButton { +image-position: right; +image: url(:/images/close.png); + + padding:1px; +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + + 0 + 30 + 380 + 640 + + + + QStackedWidget#stackedWidget_main{ + background: transparent; +} + +QStackedWidget QWidget { + background: transparent; +} + + + + 1 + + + + + + 10 + 40 + 361 + 71 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +line-height: 25px; +color: #100A44; + + + + Connect to the already created VPN server + + + Qt::AlignCenter + + + true + + + + + + 40 + 130 + 171 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Connection code + + + + + + 40 + 220 + 301 + 41 + + + + background: #181922; +border-radius: 4px; + + + 24 + + + Qt::AlignCenter + + + true + + + Connecting... + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + + 40 + 160 + 300 + 40 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +color: #333333; + + + + + + + + + 40 + 220 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + + + + Connect + + + + + + 40 + 320 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; + +color: #100A44; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +border: 1px solid #211C4A; +border-radius: 4px; +} + + + + Set up your own server + + + + + + QLabel { +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +color: #211C4A; +} + +QLineEdit { +padding-left: 10px; +border: 1px solid #A7A7A7; +} + + + + + 10 + 40 + 361 + 71 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +line-height: 25px; +color: #100A44; + + + + Connect your server to use VPN + + + Qt::AlignCenter + + + true + + + + + + 40 + 170 + 171 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Server IP address + + + + + + 40 + 255 + 261 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Login to connect via SSH + + + + + + 40 + 340 + 171 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Password + + + + + + 40 + 200 + 300 + 40 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +color: #333333; + + + + + + + + + 40 + 285 + 300 + 40 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +color: #333333; + + + root + + + + + + 40 + 370 + 300 + 40 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +color: #333333; + + + + + + QLineEdit::Password + + + + + + 40 + 440 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + + + + Connect + + + + + + 50 + 115 + 281 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 20px; +text-align: center; + +/* акцент */ +color: #15CDCB; + + + Where to get connection data → + + + + + + 40 + 440 + 301 + 41 + + + + QProgressBar{ +color:rgb(212, 212, 212); +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +background: #100A44; +border-radius: 4px; +} + +QProgressBar::chunk { +background: rgba(255, 255, 255, 0.15); +border-radius: 4px 0px 0px 4px; + +} + + + + 24 + + + Qt::AlignCenter + + + true + + + Configuring... + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 110 + 590 + 150 + 22 + + + + image: url(:/images/AmneziaVPN.png); + + + + + + + + true + + + + 40 + 490 + 301 + 41 + + + + Please wait, configuring process may take up to 5 minutes + + + true + + + progressBar_new_server_connection + label_2 + label_4 + label_5 + label_6 + lineEdit_new_server_ip + lineEdit_new_server_login + lineEdit_new_server_password + pushButton_new_server_connect_with_new_data + pushButton + pushButton_back_from_new_server + label_7 + label_new_server_wait_info + + + + + + + + + 0 + 0 + 380 + 325 + + + + PointingHandCursor + + + border-image: url(:/images/background_connected.png); + + + + + + true + + + + + + 0 + 370 + 380 + 51 + + + + + + + + + 53 + 10 + 15 + 15 + + + + image: url(:/images/download.png); + + + + + + + + + 311 + 10 + 15 + 15 + + + + image: url(:/images/upload.png); + + + + + + + + + 260 + 20 + 118 + 30 + + + + + Lato + 12 + 7 + false + false + + + + color: rgb(66, 209, 133); +font: 63 12pt "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + 0 + 20 + 127 + 30 + + + + + Lato + 12 + 7 + false + false + + + + color: rgb(65, 113, 214); +font: 63 12pt "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + + 20 + 550 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} + + + + + Add site + + + + + + 340 + 10 + 31 + 31 + + + + PointingHandCursor + + + image: url(:/images/settings.png); + + + + + + + + + 150 + 200 + 80 + 40 + + + + QPushButton:!checked { +image: url(:/images/connect_button_disconnected.png); +} + +QPushButton:checked { +image: url(:/images/connect_button_connected.png); +} + + + + + + true + + + false + + + + + + 0 + 250 + 380 + 31 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + Connected + + + Qt::AlignCenter + + + + + + 20 + 424 + 341 + 1 + + + + background-image: url(:/images/Line.png); + + + + + + + + + 20 + 450 + 281 + 31 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + + How to use VPN + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + false + + + + 20 + 490 + 341 + 19 + + + + For all connections + + + + + false + + + + 20 + 520 + 341 + 19 + + + + For selected sites + + + true + + + + + + +QListView { + outline: 0; + background: transparent; + border: none; + + gridline-color: darkgray; +} + +QListView::item +{ + padding-left: 5px; + border: none; +color: #181922; + +} + +QListView::item:disabled +{ + padding-left: 5px; + border: none; +color: #181922; +} + +QListView::item:selected { + border: none; +background: rgba(167, 167, 167, 0.1); +color: #181922; +} + + + + + 0 + 0 + 381 + 0 + + + + PointingHandCursor + + + QAbstractItemView::NoEditTriggers + + + + + + 10 + 10 + 28 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 0 + 360 + 0 + + + + List of the most popular prohibited sites + + + Qt::AlignCenter + + + true + + + + + true + + + + 19 + 50 + 341 + 41 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; + +/* or 125% */ + +/* black */ +color: #181922; + + + These sites will open via VPN + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + 20 + 200 + 341 + 361 + + + + PointingHandCursor + + + QAbstractItemView::NoEditTriggers + + + + + + 20 + 150 + 281 + 31 + + + + + Lato + -1 + 50 + false + false + + + + background: #FFFFFF; + +/* grey */ +border: 1px solid #A7A7A7; + + + + + + + Qt::AlignCenter + + + For example, rutor.org or 17.21.111.8 + + + + + true + + + + 310 + 150 + 51 + 31 + + + + PointingHandCursor + + + /* black */ +background: #181922; +border-radius: 4px; +font-size: 18pt; + + + + + + + + + true + + + + 90 + 584 + 201 + 21 + + + + PointingHandCursor + + + color: #181922; + + + Delete selected item + + + + + + 20 + 115 + 311 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* identical to box height, or 24px */ + +/* text */ +color: #333333; + + + Hostname or IP address + + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 10 + 40 + 360 + 1 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 60 + 330 + 30 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +Text-align:left; +padding-left: 30px; + + +/* black */ +color: #100A44; + +background-image: url(:/images/server_settings.png); +background-repeat: no-repeat; + background-position: left center; + + + Server settings + + + + + + 10 + 110 + 360 + 1 + + + + image: url(:/images/line.png); + + + + + + + + + 30 + 130 + 330 + 30 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; +Text-align:left; +padding-left: 30px; + + +/* black */ +color: #100A44; + +background-image: url(:/images/share.png); +background-repeat: no-repeat; + background-position: left center; + + + Share connection + + + + + + 10 + 180 + 360 + 1 + + + + image: url(:/images/line.png); + + + + + + + + + + + 10 + 10 + 26 + 20 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + true + + + + 20 + 40 + 341 + 41 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; + +/* or 125% */ + +/* black */ +color: #181922; + + + Connection string + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + 30 + 100 + 320 + 151 + + + + background: #F5F5F5; +border-radius: 10px; + + +font-family: Consolas; +font-style: normal; +font-weight: bold; +font-size: 22px; +line-height: 110%; +/* or 35px */ +text-align: center; + +color: #15CDCB; + + + + QTextEdit::FixedColumnWidth + + + 20 + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Consolas'; font-size:22px; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt;">vpn:\\aosdiufhafafsuhgqejghuserhglaidhgauhgalgadg</span></p></body></html> + + + + + + 20 + 280 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} + + + + Copy + + + + + + 30 + 350 + 321 + 101 + + + + + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; +/* or 24px */ + +/* grey */ +color: #A7A7A7; + + + + Anyone who logs in with this code will have the same rights to use the VPN as you. To create a new code, change your login and / or password for connection in your server settings. + + + Qt::AlignJustify|Qt::AlignVCenter + + + true + + + + + + + + + + + SlidingStackedWidget + QStackedWidget +
ui/Controls/SlidingStackedWidget.h
+ 1 +
+
+ + +
diff --git a/client/utils.cpp b/client/utils.cpp new file mode 100644 index 00000000..5f23bb49 --- /dev/null +++ b/client/utils.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include + +#include "defines.h" +#include "utils.h" + +QString Utils::toString(bool value) +{ + return value ? "true" : "false"; +} + +QString Utils::serverName() +{ +#ifdef Q_OS_WIN + return SERVICE_NAME; +#else + return QString("/tmp/%1").arg(SERVICE_NAME); +#endif +} + +QString Utils::defaultVpnConfigFileName() +{ + return configPath() + QString("/%1.ovpn").arg(APPLICATION_NAME); +} + +QString Utils::systemLogPath() +{ +#ifdef Q_OS_WIN + QStringList locationList = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + QString primaryLocation = "ProgramData"; + foreach (const QString& location, locationList) { + if (location.contains(primaryLocation)) { + return QString("%1/%2/log").arg(location).arg(APPLICATION_NAME); + } + } + return QString(); +#else + return QString("/var/log/%1").arg(APPLICATION_NAME); +#endif +} + +bool Utils::initializePath(const QString& path) +{ + QDir dir; + if (!dir.mkpath(path)) { + qWarning().noquote() << QString("Cannot initialize path: '%1'").arg(path); + return false; + } + return true; +} + +QString Utils::configPath() +{ + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/config"; +} + +bool Utils::createEmptyFile(const QString& path) +{ + QFile f(path); + return f.open(QIODevice::WriteOnly | QIODevice::Truncate); +} + +QString Utils::executable(const QString& baseName, bool absPath) +{ + QString ext; +#ifdef Q_OS_WIN + ext = ".exe"; +#endif + const QString fileName = baseName + ext; + if (!absPath) { + return fileName; + } + return QCoreApplication::applicationDirPath() + "/" + fileName; +} + +bool Utils::processIsRunning(const QString& fileName) +{ +#ifdef Q_OS_WIN + QProcess process; + process.setReadChannel(QProcess::StandardOutput); + process.setProcessChannelMode(QProcess::MergedChannels); + process.start(QString("wmic.exe /OUTPUT:STDOUT PROCESS get %1").arg("Caption")); + process.waitForStarted(); + process.waitForFinished(); + QString processData(process.readAll()); + QStringList processList = processData.split(QRegExp("[\r\n]"),QString::SkipEmptyParts); + foreach (const QString& rawLine, processList) { + const QString line = rawLine.simplified(); + if (line.isEmpty()) { + continue; + } + + if (line == fileName) { + return true; + } + + } + return false; +#else + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + process.start("pgrep", QStringList({fileName})); + process.waitForFinished(); + if (process.exitStatus() == QProcess::NormalExit) { + return (process.readAll().toUInt() > 0); + } + return false; +#endif +} + diff --git a/client/utils.h b/client/utils.h new file mode 100644 index 00000000..878cf01b --- /dev/null +++ b/client/utils.h @@ -0,0 +1,20 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +class Utils { + +public: + static QString configPath(); + static QString defaultVpnConfigFileName(); + static QString executable(const QString& baseName, bool absPath); + static QString serverName(); + static QString systemLogPath(); + static QString toString(bool value); + static bool createEmptyFile(const QString& path); + static bool initializePath(const QString& path); + static bool processIsRunning(const QString& fileName); +}; + +#endif // UTILS_H diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp new file mode 100644 index 00000000..1ed8f444 --- /dev/null +++ b/client/vpnconnection.cpp @@ -0,0 +1,115 @@ +#include +#include + +#include +#include + +#include "protocols/openvpnprotocol.h" +#include "utils.h" +#include "vpnconnection.h" + +VpnConnection::VpnConnection(QObject* parent) : QObject(parent) +{ + VpnProtocol::initializeCommunicator(parent); +} + +void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes) +{ + emit bytesChanged(receivedBytes, sentBytes); +} + +void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state) +{ + emit connectionStateChanged(state); +} + +ErrorCode VpnConnection::lastError() const +{ + if (!m_vpnProtocol.data()) { + return ErrorCode::InternalError; + } + + return m_vpnProtocol.data()->lastError(); +} + +ErrorCode VpnConnection::requestVpnConfig(const ServerCredentials &credentials, Protocol protocol) +{ + ErrorCode errorCode = ErrorCode::NoError; + if (protocol == Protocol::OpenVpn) { + QString configData = OpenVpnConfigurator::genOpenVpnConfig(credentials, &errorCode); + if (errorCode) { + return errorCode; + } + + QFile file(Utils::defaultVpnConfigFileName()); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + QTextStream stream(&file); + stream << configData << endl; + return ErrorCode::NoError; + } + + return ErrorCode::FailedToSaveConfigData; + } + else if (protocol == Protocol::ShadowSocks) { + // Request OpenVPN config and ShadowSocks + return ErrorCode::NotImplementedError; + } + return ErrorCode::NotImplementedError; + +} + +ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Protocol protocol) +{ + // TODO: Try protocols one by one in case of Protocol::Any + // TODO: Implement some behavior in case if connection not stable + qDebug() << "Connect to VPN"; + + if (protocol == Protocol::Any || protocol == Protocol::OpenVpn) { + ErrorCode e = requestVpnConfig(credentials, Protocol::OpenVpn); + if (e) { + return e; + } + m_vpnProtocol.reset(new OpenVpnProtocol()); + } + else if (protocol == Protocol::ShadowSocks) { + return ErrorCode::NotImplementedError; + } + + connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState))); + connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); + + return m_vpnProtocol.data()->start(); +} + +QString VpnConnection::bytesToText(quint64 bytes) +{ + return QString("%1 %2").arg(bytes / 1000000).arg(tr("Mbps")); +} + +void VpnConnection::disconnectFromVpn() +{ + qDebug() << "Disconnect from VPN"; + + if (!m_vpnProtocol.data()) { + return; + } + m_vpnProtocol.data()->stop(); +} + +bool VpnConnection::connected() const +{ + if (!m_vpnProtocol.data()) { + return false; + } + + return m_vpnProtocol.data()->connected(); +} + +bool VpnConnection::disconnected() const +{ + if (!m_vpnProtocol.data()) { + return true; + } + + return m_vpnProtocol.data()->disconnected(); +} diff --git a/client/vpnconnection.h b/client/vpnconnection.h new file mode 100644 index 00000000..0bf81851 --- /dev/null +++ b/client/vpnconnection.h @@ -0,0 +1,43 @@ +#ifndef VPNCONNECTION_H +#define VPNCONNECTION_H + +#include +#include +#include + +#include "protocols/vpnprotocol.h" +#include "core/defs.h" + +using namespace amnezia; + +class VpnConnection : public QObject +{ + Q_OBJECT + +public: + explicit VpnConnection(QObject* parent = nullptr); + ~VpnConnection() override = default; + + static QString bytesToText(quint64 bytes); + + ErrorCode lastError() const; + ErrorCode requestVpnConfig(const ServerCredentials &credentials, Protocol protocol); + ErrorCode connectToVpn(const ServerCredentials &credentials, Protocol protocol = Protocol::Any); + bool connected() const; + bool disconnected() const; + void disconnectFromVpn(); + +signals: + void bytesChanged(quint64 receivedBytes, quint64 sentBytes); + void connectionStateChanged(VpnProtocol::ConnectionState state); + +protected slots: + void onBytesChanged(quint64 receivedBytes, quint64 sentBytes); + void onConnectionStateChanged(VpnProtocol::ConnectionState state); + +protected: + + QScopedPointer m_vpnProtocol; +}; + +#endif // VPNCONNECTION_H diff --git a/deploy/data/macos/AmneziaVPN.plist b/deploy/data/macos/AmneziaVPN.plist new file mode 100644 index 00000000..8dabbc9e --- /dev/null +++ b/deploy/data/macos/AmneziaVPN.plist @@ -0,0 +1,26 @@ + + + + + Label + AmneziaVPN-service + ProgramArguments + + /Applications/AmneziaVPN.app/Contents/MacOS/AmneziaVPN-service + + KeepAlive + + Sockets + + Listeners + + SockServiceName + 5959 + SockType + stream + SockFamily + IPv4 + + + + diff --git a/deploy/data/macos/openvpn b/deploy/data/macos/openvpn new file mode 100644 index 00000000..f1c08e93 Binary files /dev/null and b/deploy/data/macos/openvpn differ diff --git a/deploy/data/macos/post_install.sh b/deploy/data/macos/post_install.sh new file mode 100644 index 00000000..95c1a570 --- /dev/null +++ b/deploy/data/macos/post_install.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +APP_NAME=AmneziaVPN +PLIST_NAME=$APP_NAME.plist +LAUNCH_DAEMONS_PLIST_NAME=/Library/LaunchDaemons/$PLIST_NAME +LOG_FOLDER=/var/log/$APP_NAME +LOG_FILE="$LOG_FOLDER/post-install.log" +APP_PATH=/Applications/$APP_NAME.app + +if launchctl list "$APP_NAME-service" &> /dev/null; then + launchctl unload $LAUNCH_DAEMONS_PLIST_NAME + rm -f $LAUNCH_DAEMONS_PLIST_NAME +fi + +tar xzf $APP_PATH/$APP_NAME.tar.gz -C $APP_PATH +rm -f $APP_PATH/$APP_NAME.tar.gz + +rm -rf $LOG_FOLDER +mkdir -p $LOG_FOLDER + +echo "`date` Script started" > $LOG_FILE + +killall -9 $APP_NAME-service 2>> $LOG_FILE + +mv -f $APP_PATH/$PLIST_NAME $LAUNCH_DAEMONS_PLIST_NAME 2>> $LOG_FILE +chown root:wheel $LAUNCH_DAEMONS_PLIST_NAME +launchctl load $LAUNCH_DAEMONS_PLIST_NAME + +echo "`date` Service status: $?" >> $LOG_FILE +echo "`date` Script finished" >> $LOG_FILE + +rm -- "$0" diff --git a/deploy/data/macos/post_uninstall.sh b/deploy/data/macos/post_uninstall.sh new file mode 100644 index 00000000..6e8e9fa8 --- /dev/null +++ b/deploy/data/macos/post_uninstall.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +APP_NAME=AmneziaVPN +PLIST_NAME=$APP_NAME.plist +LAUNCH_DAEMONS_PLIST_NAME=/Library/LaunchDaemons/$PLIST_NAME + +if launchctl list "$APP_NAME-service" &> /dev/null; then + launchctl unload $LAUNCH_DAEMONS_PLIST_NAME + rm -f $LAUNCH_DAEMONS_PLIST_NAME +fi + +rm -rf "$HOME/Library/Application Support/$APP_NAME" +rm -rf /var/log/$APP_NAME +rm -rf /Applications/$APP_NAME.app/Contents diff --git a/deploy/data/windows/easyrsa/COPYING.html b/deploy/data/windows/easyrsa/COPYING.html new file mode 100644 index 00000000..b508a99c --- /dev/null +++ b/deploy/data/windows/easyrsa/COPYING.html @@ -0,0 +1,21 @@ +

Easy-RSA -- A Shell-based CA Utility

+

Copyright (C) 2013 by the Open-Source OpenVPN development community

+

Easy-RSA 3 license: GPLv2

+

All the Easy-RSA code contained in this project falls under a GPLv2 license with +full text available in the Licensing/ directory. Additional components used by +this project fall under additional licenses:

+

Additional licenses for external components

+

The following components are under different licenses; while not part of the +Easy-RSA source code, these components are used by Easy-RSA or provided in +platform distributions as described below:

+

OpenSSL

+

OpenSSL is not linked by Easy-RSA, nor is it currently provided in any release + package by Easy-RSA. However, Easy-RSA is tightly coupled with OpenSSL, so + effective use of this code will require your acceptance and installation of + OpenSSL.

+

Additional Windows Components

+

The Windows binary package includes mksh/Win32 and unxutils binary components, + with full licensing details available in the distro/windows/Licensing/ + subdirectory of this project. mksh/Win32 is under a MirOS license (with some + additional component licenses present there) and unxutils is under a GPLv2 + license.

\ No newline at end of file diff --git a/deploy/data/windows/easyrsa/COPYING.md b/deploy/data/windows/easyrsa/COPYING.md new file mode 100644 index 00000000..39bce088 --- /dev/null +++ b/deploy/data/windows/easyrsa/COPYING.md @@ -0,0 +1,33 @@ +Easy-RSA -- A Shell-based CA Utility +==================================== + +Copyright (C) 2013 by the Open-Source OpenVPN development community + +Easy-RSA 3 license: GPLv2 +------------------------- + +All the Easy-RSA code contained in this project falls under a GPLv2 license with +full text available in the Licensing/ directory. Additional components used by +this project fall under additional licenses: + +Additional licenses for external components +------------------------------------------- + +The following components are under different licenses; while not part of the +Easy-RSA source code, these components are used by Easy-RSA or provided in +platform distributions as described below: + +### OpenSSL + + OpenSSL is not linked by Easy-RSA, nor is it currently provided in any release + package by Easy-RSA. However, Easy-RSA is tightly coupled with OpenSSL, so + effective use of this code will require your acceptance and installation of + OpenSSL. + +### Additional Windows Components + + The Windows binary package includes mksh/Win32 and unxutils binary components, + with full licensing details available in the distro/windows/Licensing/ + subdirectory of this project. mksh/Win32 is under a MirOS license (with some + additional component licenses present there) and unxutils is under a GPLv2 + license. diff --git a/deploy/data/windows/easyrsa/EasyRSA-Start.bat b/deploy/data/windows/easyrsa/EasyRSA-Start.bat new file mode 100644 index 00000000..5bd117cd --- /dev/null +++ b/deploy/data/windows/easyrsa/EasyRSA-Start.bat @@ -0,0 +1,2 @@ +@echo OFF +bin\sh.exe bin\easyrsa-shell-init.sh \ No newline at end of file diff --git a/deploy/data/windows/easyrsa/Licensing/LICENSE-OpenSSL.txt b/deploy/data/windows/easyrsa/Licensing/LICENSE-OpenSSL.txt new file mode 100644 index 00000000..e953f590 --- /dev/null +++ b/deploy/data/windows/easyrsa/Licensing/LICENSE-OpenSSL.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2018 The OpenSSL Project. 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. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/deploy/data/windows/easyrsa/Licensing/gpl-2.0.txt b/deploy/data/windows/easyrsa/Licensing/gpl-2.0.txt new file mode 100644 index 00000000..1f963da0 --- /dev/null +++ b/deploy/data/windows/easyrsa/Licensing/gpl-2.0.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/deploy/data/windows/easyrsa/Licensing/mksh-Win32.txt b/deploy/data/windows/easyrsa/Licensing/mksh-Win32.txt new file mode 100644 index 00000000..f646763b --- /dev/null +++ b/deploy/data/windows/easyrsa/Licensing/mksh-Win32.txt @@ -0,0 +1,148 @@ +Licence +------- + +mksh/Win32 is a derived work of The MirBSD Korn Shell and +recognised by The MirOS Project but realised by an independent +developer with support and legal permit by Scalaris AG. + + +The shell itself comes under The MirOS Licence: + +Copyright (c) 2002-2013 + The MirOS Project +Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Thorsten Glaser +Copyright (c) 2010, 2011, 2012, 2013 + Michael Langguth + +Provided that these terms and disclaimer and all copyright notices +are retained or reproduced in an accompanying document, permission +is granted to deal in this work without restriction, including un- +limited rights to use, publicly perform, distribute, sell, modify, +merge, give away, or sublicence. + +This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +the utmost extent permitted by applicable law, neither express nor +implied; without malicious intent or gross negligence. In no event +may a licensor, author or contributor be held liable for indirect, +direct, other damage, loss, or other issues arising in any way out +of dealing in the work, even if advised of the possibility of such +damage or existence of a defect, except proven that it results out +of said person's immediate fault when using the work as intended. + + +The shell contains strlcpy() under the ISC licence: + +Copyright (c) 2006, 2008, 2009 + Thorsten Glaser +Copyright (c) 1998 Todd C. Miller + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +This version of the shell contains setmode() under the UCB BSD licence: + +Copyright (c) 1989, 1993, 1994 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Dave Borman at Cray Research, Inc. + +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. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + + +The shell includes nedmalloc under the Boost Software License which, +in turn, includes dlmalloc under CC0 (eventually) in its binary. + + +The "liblan" portability library is covered by The MirOS Licence: + +Copyright (c) 1996, 1998, 2003, 2004, 2005, 2010, 2011, 2012, 2013 + Scalaris AG, Author: Michael Langguth + +Provided that these terms and disclaimer and all copyright notices +are retained or reproduced in an accompanying document, permission +is granted to deal in this work without restriction, including un- +limited rights to use, publicly perform, distribute, sell, modify, +merge, give away, or sublicence. + +This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +the utmost extent permitted by applicable law, neither express nor +implied; without malicious intent or gross negligence. In no event +may a licensor, author or contributor be held liable for indirect, +direct, other damage, loss, or other issues arising in any way out +of dealing in the work, even if advised of the possibility of such +damage or existence of a defect, except proven that it results out +of said person's immediate fault when using the work as intended. + + +It includes an implementation of POSIX directory browsing functions +and types for Win32 under a Historical Permission Notice variant: + +Copyright Kevlin Henney, 1997, 2003. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that this copyright and permissions notice appear in all copies and +derivatives. + +This software is supplied "as is" without express or implied warranty. + +But that said, if there are any problems please get in touch. + + +The program shortcut (mkshicon1.ico) is an unregistered trademark: + +Copyright (c) 2013 Michael Langguth +Copyright (c) 2006 Benny Siegert +Copyright (c) 2005 Thorsten Glaser + +This icon may be used to refer to The MirBSD Korn Shell and +its Win32 port. Distribution patches are acceptable as long +as they modify $KSH_VERSION according to the guidelines that +are published on the website; forks and works that are not +derivates are not allowed to use it. + +The BSD daemon is Copyright (c) 1988 by Marshall Kirk McKusick. +All Rights Reserved. Individuals may use the daemon for their +personal use within the bounds of good taste. When reasonably +possible, the text shown above is to be included. + +The Shilouette daemon is Copyright (c) 2003 by Rick Collette. +The MirOS Project may freely use the former ekkoBSD Logo, +the shilouette Daemon, for MirBSD, on anything the project +leader sees fit, so long as it pertains to MirBSD in some +way and the leader gives credit for the original daemon to +Marshall Kirk McKusick. diff --git a/deploy/data/windows/easyrsa/Licensing/mktemp.txt b/deploy/data/windows/easyrsa/Licensing/mktemp.txt new file mode 100644 index 00000000..4fe81eff --- /dev/null +++ b/deploy/data/windows/easyrsa/Licensing/mktemp.txt @@ -0,0 +1,20 @@ +Mktemp is distributed under the following ISC-style license: + + Copyright (c) 1996-1997, 2000-2001, 2008, 2010 + Todd C. Miller + Copyright (c) 1996, David Mazieres + Copyright (c) 2008, Damien Miller + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +From https://www.mktemp.org/mktemp/license.html diff --git a/deploy/data/windows/easyrsa/bin/awk.exe b/deploy/data/windows/easyrsa/bin/awk.exe new file mode 100644 index 00000000..aa1fada8 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/awk.exe differ diff --git a/deploy/data/windows/easyrsa/bin/cat.exe b/deploy/data/windows/easyrsa/bin/cat.exe new file mode 100644 index 00000000..6a6af4df Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/cat.exe differ diff --git a/deploy/data/windows/easyrsa/bin/cp.exe b/deploy/data/windows/easyrsa/bin/cp.exe new file mode 100644 index 00000000..60f1cc2b Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/cp.exe differ diff --git a/deploy/data/windows/easyrsa/bin/date.exe b/deploy/data/windows/easyrsa/bin/date.exe new file mode 100644 index 00000000..069bae14 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/date.exe differ diff --git a/deploy/data/windows/easyrsa/bin/diff.exe b/deploy/data/windows/easyrsa/bin/diff.exe new file mode 100644 index 00000000..2797ffd0 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/diff.exe differ diff --git a/deploy/data/windows/easyrsa/bin/easyrsa-shell-init.sh b/deploy/data/windows/easyrsa/bin/easyrsa-shell-init.sh new file mode 100644 index 00000000..82d4dec1 --- /dev/null +++ b/deploy/data/windows/easyrsa/bin/easyrsa-shell-init.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# shellcheck disable=SC2161,SC1091 + +# This script is a frontend designed to create & launch a POSIX shell +# environment suitable for use with Easy-RSA. mksh/Win32 is used with this +# project; use with other POSIX shells for Windows may require modification to +# this wrapper script. + +setup_path="${EASYRSA:-$PWD}" +export PATH="$setup_path;$setup_path/bin;$PATH" +export HOME="$setup_path" + +# This prevents reading from a user's .mkshrc if they have one. +# A user who runs mksh for other purposes might have it +export ENV="/disable-env" + +# Verify required externals are present +extern_list="which awk cat cp mkdir printf rm" +for f in $extern_list; do + if ! which "${f}.exe" >/dev/null 2>&1; then + echo "" + echo "FATAL: EasyRSA Shell init is missing a required external file:" + echo " ${f}.exe" + echo " Your installation is incomplete and cannot function without the required" + echo " files." + echo "" + echo " Press enter to exit." + #shellcheck disable=SC2162 + read + exit 1 + fi +done + +# set_var is defined as any vars file needs it. +# This is the same as in easyrsa, but we _don't_ export +set_var() { + var="$1" + shift + value="$*" + eval "$var=\"\${$var-$value}\"" +} #=> set_var() + +# Check for a usable openssl bin, referencing vars if present +[ -r "vars" ] && EASYRSA_CALLER=1 . "vars" 2>/dev/null +if [ -z "$EASYRSA_OPENSSL" ] && ! which openssl.exe >/dev/null 2>&1; then + echo "WARNING: openssl isn't in your system PATH. The openssl binary must be" + echo " available in the PATH, defined in the 'vars' file, or defined in a" + echo " named environment variable. See README-Windows.txt for more info." +fi + +[ -f "$setup_path/easyrsa" ] || { + echo "Missing easyrsa script. Expected to find it at: $setup_path/easyrsa" + exit 2 +} + +# Set prompt and welcome message +export PS1=' +EasyRSA Shell +# ' +echo "" +echo "Welcome to the EasyRSA 3 Shell for Windows." +echo "Easy-RSA 3 is available under a GNU GPLv2 license." +echo "" +echo "Invoke './easyrsa' to call the program. Without commands, help is displayed." + +# Drop to a shell and await input +bin/sh diff --git a/deploy/data/windows/easyrsa/bin/grep.exe b/deploy/data/windows/easyrsa/bin/grep.exe new file mode 100644 index 00000000..427f92fc Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/grep.exe differ diff --git a/deploy/data/windows/easyrsa/bin/ls.exe b/deploy/data/windows/easyrsa/bin/ls.exe new file mode 100644 index 00000000..388af5eb Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/ls.exe differ diff --git a/deploy/data/windows/easyrsa/bin/md5sum.exe b/deploy/data/windows/easyrsa/bin/md5sum.exe new file mode 100644 index 00000000..1640ba81 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/md5sum.exe differ diff --git a/deploy/data/windows/easyrsa/bin/mkdir.exe b/deploy/data/windows/easyrsa/bin/mkdir.exe new file mode 100644 index 00000000..83e57d97 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/mkdir.exe differ diff --git a/deploy/data/windows/easyrsa/bin/mktemp.exe b/deploy/data/windows/easyrsa/bin/mktemp.exe new file mode 100644 index 00000000..d9345717 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/mktemp.exe differ diff --git a/deploy/data/windows/easyrsa/bin/mv.exe b/deploy/data/windows/easyrsa/bin/mv.exe new file mode 100644 index 00000000..bcdc9d0e Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/mv.exe differ diff --git a/deploy/data/windows/easyrsa/bin/printf.exe b/deploy/data/windows/easyrsa/bin/printf.exe new file mode 100644 index 00000000..9060224b Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/printf.exe differ diff --git a/deploy/data/windows/easyrsa/bin/rm.exe b/deploy/data/windows/easyrsa/bin/rm.exe new file mode 100644 index 00000000..c489316c Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/rm.exe differ diff --git a/deploy/data/windows/easyrsa/bin/sed.exe b/deploy/data/windows/easyrsa/bin/sed.exe new file mode 100644 index 00000000..2a9f38c4 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/sed.exe differ diff --git a/deploy/data/windows/easyrsa/bin/sh.exe b/deploy/data/windows/easyrsa/bin/sh.exe new file mode 100644 index 00000000..a42d9962 Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/sh.exe differ diff --git a/deploy/data/windows/easyrsa/bin/which.exe b/deploy/data/windows/easyrsa/bin/which.exe new file mode 100644 index 00000000..fbf68efc Binary files /dev/null and b/deploy/data/windows/easyrsa/bin/which.exe differ diff --git a/deploy/data/windows/easyrsa/easyrsa b/deploy/data/windows/easyrsa/easyrsa new file mode 100644 index 00000000..711ae712 --- /dev/null +++ b/deploy/data/windows/easyrsa/easyrsa @@ -0,0 +1,2579 @@ +#!/bin/sh + +# Easy-RSA 3 -- A Shell-based CA Utility +# +# Copyright (C) 2018 by the Open-Source OpenVPN development community. +# A full list of contributors can be found in the ChangeLog. +# +# This code released under version 2 of the GNU GPL; see COPYING and the +# Licensing/ directory of this project for full licensing details. + +# Help/usage output to stdout +usage() { + # command help: + print " +Easy-RSA 3 usage and overview + +USAGE: easyrsa [options] COMMAND [command-options] + +A list of commands is shown below. To get detailed usage and help for a +command, run: + ./easyrsa help COMMAND + +For a listing of options that can be supplied before the command, use: + ./easyrsa help options + +Here is the list of commands available with a short syntax reminder. Use the +'help' command above to get full usage details. + + init-pki + build-ca [ cmd-opts ] + gen-dh + gen-req [ cmd-opts ] + sign-req + build-client-full [ cmd-opts ] + build-server-full [ cmd-opts ] + revoke [cmd-opts] + renew [cmd-opts] + build-serverClient-full [ cmd-opts ] + gen-crl + update-db + show-req [ cmd-opts ] + show-cert [ cmd-opts ] + show-ca [ cmd-opts ] + import-req + export-p7 [ cmd-opts ] + export-p8 [ cmd-opts ] + export-p12 [ cmd-opts ] + set-rsa-pass [ cmd-opts ] + set-ec-pass [ cmd-opts ] + upgrade +" + + # collect/show dir status: + err_source="Not defined: vars autodetect failed and no value provided" + work_dir="${EASYRSA:-$err_source}" + pki_dir="${EASYRSA_PKI:-$err_source}" + print "\ +DIRECTORY STATUS (commands would take effect on these locations) + EASYRSA: $work_dir + PKI: $pki_dir +" +} # => usage() + +# Detailed command help +# When called with no args, calls usage(), otherwise shows help for a command +cmd_help() { + text="" + opts="" + case "$1" in + init-pki|clean-all) text=" + init-pki [ cmd-opts ] + Removes & re-initializes the PKI dir for a clean PKI" ;; + build-ca) text=" + build-ca [ cmd-opts ] + Creates a new CA" + opts=" + nopass - do not encrypt the CA key (default is encrypted) + subca - create an intermediate CA keypair and request (default is a root CA) + intca - alias to the above" ;; + gen-dh) text=" + gen-dh + Generates DH (Diffie-Hellman) parameters" ;; + gen-req) text=" + gen-req [ cmd-opts ] + Generate a standalone keypair and request (CSR) + + This request is suitable for sending to a remote CA for signing." + opts=" + nopass - do not encrypt the private key (default is encrypted)" ;; + sign|sign-req) text=" + sign-req + Sign a certificate request of the defined type. must be a known + type such as 'client', 'server', 'serverClient', or 'ca' (or a user-added type.) + + This request file must exist in the reqs/ dir and have a .req file + extension. See import-req below for importing reqs from other sources." ;; + build|build-client-full|build-server-full|build-serverClient-full) text=" + build-client-full [ cmd-opts ] + build-server-full [ cmd-opts ] + build-serverClient-full [ cmd-opts ] + Generate a keypair and sign locally for a client and/or server + + This mode uses the as the X509 CN." + opts=" + nopass - do not encrypt the private key (default is encrypted) + inline - create an inline credentials file for this node" ;; + revoke) text=" + revoke [reason] + Revoke a certificate specified by the filename_base, with an optional + revocation reason that is one of: + unspecified + keyCompromise + CACompromise + affiliationChanged + superseded + cessationOfOperation + certificateHold";; + renew) text=" + renew [ cmd-opts ] + Renew a certificate specified by the filename_base" + opts=" + nopass - do not encrypt the private key (default is encrypted)" ;; + gen-crl) text=" + gen-crl + Generate a CRL" ;; + update-db) text=" + update-db + Update the index.txt database + + This command will use the system time to update the status of issued + certificates." ;; + show-req|show-cert) text=" + show-req [ cmd-opts ] + show-cert [ cmd-opts ] + Shows details of the req or cert referenced by filename_base + + Human-readable output is shown, including any requested cert options when + showing a request." + opts=" + full - show full req/cert info, including pubkey/sig data" ;; + show-ca) text=" + show-ca [ cmd-opts ] + Shows details of the CA cert + + Human-readable output is shown." + opts=" + full - show full cert info, including pubkey/sig data" ;; + import-req) text=" + import-req + Import a certificate request from a file + + This will copy the specified file into the reqs/ dir in + preparation for signing. + The is the filename base to create. + + Example usage: + import-req /some/where/bob_request.req bob" ;; + export-p12) text=" + export-p12 [ cmd-opts ] + Export a PKCS#12 file with the keypair specified by " + opts=" + noca - do not include the ca.crt file in the PKCS12 output + nokey - do not include the private key in the PKCS12 output" ;; + export-p7) text=" + export-p7 [ cmd-opts ] + Export a PKCS#7 file with the pubkey specified by " + opts=" + noca - do not include the ca.crt file in the PKCS7 output" ;; + export-p8) text=" + export-p8 [ cmd-opts ] + Export a PKCS#8 file with the private key specified by " + opts=" + noca - do not include the ca.crt file in the PKCS7 output" ;; + set-rsa-pass|set-ec-pass) text=" + set-rsa-pass [ cmd-opts ] + set-ec-pass [ cmd-opts ] + Set a new passphrase on an RSA or EC key for the listed ." + opts=" + nopass - use no password and leave the key unencrypted + file - (advanced) treat the file as a raw path, not a short-name" ;; + upgrade) text=" + upgrade + Upgrade EasyRSA PKI and/or CA. must be one of: + pki - Upgrade EasyRSA v2.x PKI to EasyRSA v3.x PKI (includes CA below) + ca - Upgrade EasyRSA v3.0.5 CA or older to EasyRSA v3.0.6 CA or later." ;; + altname|subjectaltname|san) text=" + --subject-alt-name=SAN_FORMAT_STRING + This global option adds a subjectAltName to the request or issued + certificate. It MUST be in a valid format accepted by openssl or + req/cert generation will fail. Note that including multiple such names + requires them to be comma-separated; further invocations of this + option will REPLACE the value. + + Examples of the SAN_FORMAT_STRING shown below: + DNS:alternate.example.net + DNS:primary.example.net,DNS:alternate.example.net + IP:203.0.113.29 + email:alternate@example.net" ;; + options) + opt_usage ;; + "") + usage ;; + *) text=" + Unknown command: '$1' (try without commands for a list of commands)" ;; + esac + + # display the help text + print "$text" + [ -n "$opts" ] && print " + cmd-opts is an optional set of command options from this list: +$opts" +} # => cmd_help() + +# Options usage +opt_usage() { + print " +Easy-RSA Global Option Flags + +The following options may be provided before the command. Options specified +at runtime override env-vars and any 'vars' file in use. Unless noted, +non-empty values to options are mandatory. + +General options: + +--batch : set automatic (no-prompts when possible) mode +--passin=ARG : set -passin ARG for openssl +--passout=ARG : set -passout ARG for openssl +--pki-dir=DIR : declares the PKI directory +--vars=FILE : define a specific 'vars' file to use for Easy-RSA config +--version : prints EasyRSA version and build information, then exits + +Certificate & Request options: (these impact cert/req field values) + +--days=# : sets the signing validity to the specified number of days +--digest=ALG : digest to use in the requests & certificates +--dn-mode=MODE : DN mode to use (cn_only or org) +--keysize=# : size in bits of keypair to generate +--req-cn=NAME : default CN to use +--subca-len=# : path length of signed intermediate CA certs; must be >= 0 if used +--subject-alt-name : Add a subjectAltName. For more info and syntax, see: + ./easyrsa help altname +--use-algo=ALG : crypto alg to use: choose rsa (default) or ec +--curve=NAME : for elliptic curve, sets the named curve to use +--copy-ext : Copy included request X509 extensions (namely subjAltName + +Organizational DN options: (only used with the 'org' DN mode) + (values may be blank for org DN options) + +--req-c=CC : country code (2-letters) +--req-st=NAME : State/Province +--req-city=NAME : City/Locality +--req-org=NAME : Organization +--req-email=NAME : Email addresses +--req-ou=NAME : Organizational Unit + +Deprecated features: + +--ns-cert=YESNO : yes or no to including deprecated NS extensions +--ns-comment=COMMENT : NS comment to include (value may be blank) +" +} # => opt_usage() + +# Wrapper around printf - clobber print since it's not POSIX anyway +# shellcheck disable=SC1117 +print() { printf "%s\n" "$*" || exit 1; } + +# Exit fatally with a message to stderr +# present even with EASYRSA_BATCH as these are fatal problems +die() { + print " +Easy-RSA error: + +$1" 1>&2 + exit "${2:-1}" +} # => die() + +# non-fatal warning output +warn() { + [ ! "$EASYRSA_BATCH" ] && \ + print " +$1" 1>&2 + + return 0 +} # => warn() + +# informational notices to stdout +notice() { + [ ! "$EASYRSA_BATCH" ] && \ + print " +$1" + + return 0 +} # => notice() + +# yes/no case-insensitive match (operates on stdin pipe) +# Returns 0 when input contains yes, 1 for no, 2 for no match +# If both strings are present, returns 1; first matching line returns. +awk_yesno() { + #shellcheck disable=SC2016 + awkscript=' +BEGIN {IGNORECASE=1; r=2} +{ if(match($0,"no")) {r=1; exit} + if(match($0,"yes")) {r=0; exit} +} END {exit r}' + awk "$awkscript" +} # => awk_yesno() + +# intent confirmation helper func +# returns without prompting in EASYRSA_BATCH +confirm() { + [ "$EASYRSA_BATCH" ] && return + prompt="$1" + value="$2" + msg="$3" + input="" + print " +$msg + +Type the word '$value' to continue, or any other input to abort." + printf %s " $prompt" + #shellcheck disable=SC2162 + read input + [ "$input" = "$value" ] && return + notice "Aborting without confirmation." + exit 9 +} # => confirm() + +# mktemp wrapper +easyrsa_mktemp() { + [ -n "$EASYRSA_TEMP_DIR_session" ] || die "EASYRSA_TEMP_DIR_session not initialized!" + [ -d "$EASYRSA_TEMP_DIR_session" ] || mkdir -p "$EASYRSA_TEMP_DIR_session" || + die "Could not create temporary directory '$EASYRSA_TEMP_DIR_session'. Permission or concurrency problem?" + [ -d "$EASYRSA_TEMP_DIR_session" ] || die "Temporary directory '$EASYRSA_TEMP_DIR_session' does not exist" + + template="$EASYRSA_TEMP_DIR_session/tmp.XXXXXX" + tempfile=$(mktemp "$template") || return + + # win32 mktemp shipped by easyrsa returns template as file! + if [ "$template" = "$tempfile" ]; then + # but win32 mktemp -d does work + # but win32 mktemp -u does not work + tempfile=$(mktemp -du "$tempfile") || return + printf "" > "$tempfile" || return + fi + echo "$tempfile" +} # => easyrsa_mktemp + +# remove temp files and do terminal cleanups +cleanup() { + [ -z "$EASYRSA_TEMP_DIR_session" ] || rm -rf "$EASYRSA_TEMP_DIR_session" + # shellcheck disable=SC2039 + (stty echo 2>/dev/null) || { (set -o echo 2>/dev/null) && set -o echo; } + echo "" # just to get a clean line +} # => cleanup() + +easyrsa_openssl() { + openssl_command=$1; shift + + case $openssl_command in + makesafeconf) has_config=true;; + ca|req|srp|ts) has_config=true;; + *) has_config=false;; + esac + + if ! $has_config; then + "$EASYRSA_OPENSSL" "$openssl_command" "$@" + return + fi + + easyrsa_openssl_conf=$(easyrsa_mktemp) || die "Failed to create temporary file" + easyrsa_extra_exts= + if [ -n "$EASYRSA_EXTRA_EXTS" ]; then + easyrsa_extra_exts=$(easyrsa_mktemp) || die "Failed to create temporary file" + cat >"$easyrsa_extra_exts" <<-EOF + req_extensions = req_extra + [ req_extra ] + $EASYRSA_EXTRA_EXTS + EOF + fi + + # Make LibreSSL safe config file from OpenSSL config file + sed \ + -e "s\`ENV::EASYRSA\`EASYRSA\`g" \ + -e "s\`\$dir\`$EASYRSA_PKI\`g" \ + -e "s\`\$EASYRSA_PKI\`$EASYRSA_PKI\`g" \ + -e "s\`\$EASYRSA_CERT_EXPIRE\`$EASYRSA_CERT_EXPIRE\`g" \ + -e "s\`\$EASYRSA_CRL_DAYS\`$EASYRSA_CRL_DAYS\`g" \ + -e "s\`\$EASYRSA_DIGEST\`$EASYRSA_DIGEST\`g" \ + -e "s\`\$EASYRSA_KEY_SIZE\`$EASYRSA_KEY_SIZE\`g" \ + -e "s\`\$EASYRSA_DIGEST\`$EASYRSA_DIGEST\`g" \ + -e "s\`\$EASYRSA_DN\`$EASYRSA_DN\`g" \ + -e "s\`\$EASYRSA_REQ_COUNTRY\`$EASYRSA_REQ_COUNTRY\`g" \ + -e "s\`\$EASYRSA_REQ_PROVINCE\`$EASYRSA_REQ_PROVINCE\`g" \ + -e "s\`\$EASYRSA_REQ_CITY\`$EASYRSA_REQ_CITY\`g" \ + -e "s\`\$EASYRSA_REQ_ORG\`$EASYRSA_REQ_ORG\`g" \ + -e "s\`\$EASYRSA_REQ_OU\`$EASYRSA_REQ_OU\`g" \ + -e "s\`\$EASYRSA_REQ_CN\`$EASYRSA_REQ_CN\`g" \ + -e "s\`\$EASYRSA_REQ_EMAIL\`$EASYRSA_REQ_EMAIL\`g" \ + ${EASYRSA_EXTRA_EXTS:+-e "/^#%EXTRA_EXTS%/r $easyrsa_extra_exts"} \ + "$EASYRSA_SSL_CONF" > "$easyrsa_openssl_conf" || + die "Failed to update $easyrsa_openssl_conf" + + if [ "$openssl_command" = "makesafeconf" ]; then + cp "$easyrsa_openssl_conf" "$EASYRSA_SAFE_CONF" + err=$? + else + "$EASYRSA_OPENSSL" "$openssl_command" -config "$easyrsa_openssl_conf" "$@" + err=$? + fi + + rm -f "$easyrsa_openssl_conf" + rm -f "$easyrsa_extra_exts" + return $err +} # => easyrsa_openssl + +vars_source_check() { + # Check for defined EASYRSA_PKI + [ -n "$EASYRSA_PKI" ] || die "\ +EASYRSA_PKI env-var undefined" +} # => vars_source_check() + +# Verify supplied curve exists and generate curve file if needed +verify_curve_ec() { + if ! "$EASYRSA_OPENSSL" ecparam -name "$EASYRSA_CURVE" > /dev/null; then + die "\ +Curve $EASYRSA_CURVE not found. Run openssl ecparam -list_curves to show a +list of supported curves." + fi + + # Check that the ecparams dir exists + [ -d "$EASYRSA_EC_DIR" ] || mkdir "$EASYRSA_EC_DIR" || die "\ +Failed creating ecparams dir (permissions?) at: +$EASYRSA_EC_DIR" + + # Check that the required ecparams file exists + out="$EASYRSA_EC_DIR/${EASYRSA_CURVE}.pem" + [ -f "$out" ] && return 0 + "$EASYRSA_OPENSSL" ecparam -name "$EASYRSA_CURVE" -out "$out" || die "\ +Failed to generate ecparam file (permissions?) when writing to: +$out" + + # Explicitly return success for caller + return 0 +} + +# Verify if Edward Curve exists +verify_curve_ed() { + if [ "ed25519" = "$EASYRSA_CURVE" ] && "$EASYRSA_OPENSSL" genpkey -algorithm ED25519 > /dev/null; then + return 0 + elif [ "ed448" = "$EASYRSA_CURVE" ] && "$EASYRSA_OPENSSL" genpkey -algorithm ED448 > /dev/null; then + return 0 + fi + die "Curve $EASYRSA_CURVE not found." +} + +verify_ssl_lib () { + # Verify EASYRSA_OPENSSL command gives expected output + if [ -z "$EASYRSA_SSL_OK" ]; then + val="$("$EASYRSA_OPENSSL" version)" + case "${val%% *}" in + OpenSSL|LibreSSL) + print "\ +Using SSL: $EASYRSA_OPENSSL $("$EASYRSA_OPENSSL" version)" ;; + *) die "\ +Missing or invalid OpenSSL +Expected to find openssl command at: $EASYRSA_OPENSSL" ;; + esac + fi + EASYRSA_SSL_OK=1 + + # Verify EASYRSA_SSL_CONF file exists + [ -f "$EASYRSA_SSL_CONF" ] || die "\ +The OpenSSL config file cannot be found. +Expected location: $EASYRSA_SSL_CONF" +} # => verify_ssl_lib () + +# Basic sanity-check of PKI init and complain if missing +verify_pki_init() { + help_note="Run easyrsa without commands for usage and command help." + + # check that the pki dir exists + vars_source_check + [ -d "$EASYRSA_PKI" ] || die "\ +EASYRSA_PKI does not exist (perhaps you need to run init-pki)? +Expected to find the EASYRSA_PKI at: $EASYRSA_PKI +$help_note" + + # verify expected dirs present: + for i in private reqs; do + [ -d "$EASYRSA_PKI/$i" ] || die "\ +Missing expected directory: $i (perhaps you need to run init-pki?) +$help_note" + done + + # verify ssl lib + verify_ssl_lib +} # => verify_pki_init() + +# Verify core CA files present +verify_ca_init() { + help_note="Run without commands for usage and command help." + + # First check the PKI has been initialized + verify_pki_init + + # Verify expected files are present. Allow files to be regular files + # (or symlinks), but also pipes, for flexibility with ca.key + for i in serial index.txt index.txt.attr ca.crt private/ca.key; do + if [ ! -f "$EASYRSA_PKI/$i" ] && [ ! -p "$EASYRSA_PKI/$i" ]; then + [ "$1" = "test" ] && return 1 + die "\ +Missing expected CA file: $i (perhaps you need to run build-ca?) +$help_note" + fi + done + + # When operating in 'test' mode, return success. + # test callers don't care about CA-specific dir structure + [ "$1" = "test" ] && return 0 + + # verify expected CA-specific dirs: + for i in issued certs_by_serial + do + [ -d "$EASYRSA_PKI/$i" ] || die "\ +Missing expected CA dir: $i (perhaps you need to run build-ca?) +$help_note" + done + + # explicitly return success for callers + return 0 + +} # => verify_ca_init() + +# init-pki backend: +init_pki() { + + # If EASYRSA_PKI exists, confirm before we rm -rf (skiped with EASYRSA_BATCH) + if [ -e "$EASYRSA_PKI" ]; then + confirm "Confirm removal: " "yes" " +WARNING!!! + +You are about to remove the EASYRSA_PKI at: $EASYRSA_PKI +and initialize a fresh PKI here." + # now remove it: + rm -rf "$EASYRSA_PKI" || die "Removal of PKI dir failed. Check/correct errors above" + fi + + # new dirs: + for i in private reqs; do + mkdir -p "$EASYRSA_PKI/$i" || die "Failed to create PKI file structure (permissions?)" + done + + # Create $EASYRSA_SAFE_CONF ($OPENSSL_CONF) prevents bogus warnings (especially useful on win32) + if [ ! -f "$EASYRSA_SSL_CONF" ] && [ -f "$EASYRSA/openssl-easyrsa.cnf" ]; + then + cp "$EASYRSA/openssl-easyrsa.cnf" "$EASYRSA_SSL_CONF" + easyrsa_openssl makesafeconf + fi + + notice "\ +init-pki complete; you may now create a CA or requests. +Your newly created PKI dir is: $EASYRSA_PKI +" + return 0 +} # => init_pki() + +hide_read_pass() +{ + # shellcheck disable=SC2039 + if stty -echo 2>/dev/null; then + read -r "$@" + stty echo + elif (set +o echo 2>/dev/null); then + set +o echo + read -r "$@" + set -o echo + elif (echo | read -r -s 2>/dev/null) ; then + read -r -s "$@" + else + warn "Could not disable echo. Password will be shown on screen!" + read -r "$@" + fi +} # => hide_read_pass() + +# build-ca backend: +build_ca() { + opts="" + sub_ca="" + nopass="" + crypto="-aes256" + while [ -n "$1" ]; do + case "$1" in + intca) sub_ca=1 ;; + subca) sub_ca=1 ;; + nopass) nopass=1 ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + verify_pki_init + [ "$EASYRSA_ALGO" = "ec" ] && verify_curve_ec + [ "$EASYRSA_ALGO" = "ed" ] && verify_curve_ed + + # setup for the simpler intermediate CA situation and overwrite with root-CA if needed: + out_file="$EASYRSA_PKI/reqs/ca.req" + out_key="$EASYRSA_PKI/private/ca.key" + if [ ! $sub_ca ]; then + out_file="$EASYRSA_PKI/ca.crt" + opts="$opts -x509 -days $EASYRSA_CA_EXPIRE " + fi + + # Test for existing CA, and complain if already present + if verify_ca_init test; then + die "\ +Unable to create a CA as you already seem to have one set up. +If you intended to start a new CA, run init-pki first." + fi + # If a private key exists here, a intermediate ca was created but not signed. + # Notify the user and require a signed ca.crt or a init-pki: + [ -f "$out_key" ] && \ + die "\ +A CA private key exists but no ca.crt is found in your PKI dir of: +$EASYRSA_PKI +Refusing to create a new CA keypair as this operation would overwrite your +current CA keypair. If you intended to start a new CA, run init-pki first." + + # create necessary files and dirs: + err_file="Unable to create necessary PKI files (permissions?)" + for i in issued certs_by_serial \ + revoked/certs_by_serial revoked/private_by_serial revoked/reqs_by_serial \ + renewed/certs_by_serial renewed/private_by_serial renewed/reqs_by_serial; + do + mkdir -p "$EASYRSA_PKI/$i" || die "$err_file" + done + printf "" > "$EASYRSA_PKI/index.txt" || die "$err_file" + printf "" > "$EASYRSA_PKI/index.txt.attr" || die "$err_file" + print "01" > "$EASYRSA_PKI/serial" || die "$err_file" + + # Default CN only when not in global EASYRSA_BATCH mode: + # shellcheck disable=SC2015 + [ "$EASYRSA_BATCH" ] && opts="$opts -batch" || export EASYRSA_REQ_CN="Easy-RSA CA" + + out_key_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + out_file_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + # Get password from user if necessary + if [ ! $nopass ] && ( [ -z "$EASYRSA_PASSOUT" ] || [ -z "$EASYRSA_PASSIN" ] ); then + out_key_pass_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + echo + printf "Enter New CA Key Passphrase: " + hide_read_pass kpass + echo + printf "Re-Enter New CA Key Passphrase: " + hide_read_pass kpass2 + echo + # shellcheck disable=2154 + if [ "$kpass" = "$kpass2" ]; + then + printf "%s" "$kpass" > "$out_key_pass_tmp" + else + die "Passphrases do not match." + fi + fi + + # create the CA key using AES256 + crypto_opts="" + if [ ! $nopass ]; then + crypto_opts="$crypto" + if [ -z "$EASYRSA_PASSOUT" ]; then + if [ "ed" = "$EASYRSA_ALGO" ]; then + crypto_opts="$crypto_opts -pass file:$out_key_pass_tmp" + else + crypto_opts="$crypto_opts -passout file:$out_key_pass_tmp" + fi + fi + fi + if [ "$EASYRSA_ALGO" = "rsa" ]; then + #shellcheck disable=SC2086 + "$EASYRSA_OPENSSL" genrsa -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} "$EASYRSA_ALGO_PARAMS" || \ + die "Failed create CA private key" + elif [ "$EASYRSA_ALGO" = "ec" ]; then + #shellcheck disable=SC2086 + "$EASYRSA_OPENSSL" ecparam -in "$EASYRSA_ALGO_PARAMS" -genkey | \ + "$EASYRSA_OPENSSL" ec -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + elif [ "ed" = "$EASYRSA_ALGO" ]; then + if [ "ed25519" = "$EASYRSA_CURVE" ]; then + "$EASYRSA_OPENSSL" genpkey -algorithm ED25519 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + elif [ "ed448" = "$EASYRSA_CURVE" ]; then + "$EASYRSA_OPENSSL" genpkey -algorithm ED448 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + fi + fi + + # create the CA keypair: + crypto_opts="" + [ ! $nopass ] && [ -z "$EASYRSA_PASSIN" ] && crypto_opts="-passin file:$out_key_pass_tmp" + + #shellcheck disable=SC2086 + easyrsa_openssl req -utf8 -new -key "$out_key_tmp" \ + -keyout "$out_key_tmp" -out "$out_file_tmp" $crypto_opts $opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || \ + die "Failed to build the CA" + + mv "$out_key_tmp" "$out_key" + mv "$out_file_tmp" "$out_file" + [ -f "$out_key_pass_tmp" ] && rm "$out_key_pass_tmp" + + # Success messages + if [ $sub_ca ]; then + notice "\ +NOTE: Your intermediate CA request is at $out_file +and now must be sent to your parent CA for signing. Place your resulting cert +at $EASYRSA_PKI/ca.crt prior to signing operations. +" + else notice "\ +CA creation complete and you may now import and sign cert requests. +Your new CA certificate file for publishing is at: +$out_file +" + fi + return 0 +} # => build_ca() + +# gen-dh backend: +gen_dh() { + verify_pki_init + + out_file="$EASYRSA_PKI/dh.pem" + + # check to see if we already have a dh parameters file + if [ -e "$EASYRSA_PKI/dh.pem" ]; then + if [ "$EASYRSA_BATCH" = "1" ]; then + # if batch is enabled, die + die "file $EASYRSA_PKI/dh.pem already exists!" + else + # warn the user, give them a chance to force overwrite + confirm "Overwrite? " "yes" "*** File $EASYRSA_PKI/dh.pem already exists! ***" + fi + fi + + "$EASYRSA_OPENSSL" dhparam -out "$out_file" "$EASYRSA_KEY_SIZE" || \ + die "Failed to build DH params" + notice "\ +DH parameters of size $EASYRSA_KEY_SIZE created at $out_file +" + return 0 +} # => gen_dh() + +# gen-req backend: +gen_req() { + # pull filename base and use as default interactive CommonName: + [ -n "$1" ] || die "\ +Error: gen-req must have a file base as the first argument. +Run easyrsa without commands for usage and commands." + key_out="$EASYRSA_PKI/private/$1.key" + req_out="$EASYRSA_PKI/reqs/$1.req" + [ ! "$EASYRSA_BATCH" ] && EASYRSA_REQ_CN="$1" + shift + + # function opts support + opts= + while [ -n "$1" ]; do + case "$1" in + nopass) opts="$opts -nodes" ;; + # batch flag supports internal callers needing silent operation + batch) EASYRSA_BATCH=1 ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + verify_pki_init + [ "$EASYRSA_ALGO" = "ec" ] && verify_curve_ec + [ "$EASYRSA_ALGO" = "ed" ] && verify_curve_ed + + # don't wipe out an existing private key without confirmation + [ -f "$key_out" ] && confirm "Confirm key overwrite: " "yes" "\ + +WARNING!!! + +An existing private key was found at $key_out +Continuing with key generation will replace this key." + + # When EASYRSA_EXTRA_EXTS is defined, append it to openssl's [req] section: + if [ -n "$EASYRSA_EXTRA_EXTS" ]; then + # Setup & insert the extra ext data keyed by a magic line + extra_exts=" +req_extensions = req_extra +[ req_extra ] +$EASYRSA_EXTRA_EXTS" + #shellcheck disable=SC2016 + awkscript=' +{if ( match($0, "^#%EXTRA_EXTS%") ) + { while ( getline<"/dev/stdin" ) {print} next } + {print} +}' + conf_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + print "$extra_exts" | \ + awk "$awkscript" "$EASYRSA_SSL_CONF" \ + > "$conf_tmp" \ + || die "Copying SSL config to temp file failed" + # Use this new SSL config for the rest of this function + EASYRSA_SSL_CONF="$conf_tmp" + fi + + key_out_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + req_out_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + # generate request + [ $EASYRSA_BATCH ] && opts="$opts -batch" + # shellcheck disable=2086,2148 + algo_opts="" + if [ "ed" = "$EASYRSA_ALGO" ]; then + algo_opts=" -newkey $EASYRSA_CURVE " + else + algo_opts=" -newkey $EASYRSA_ALGO:$EASYRSA_ALGO_PARAMS " + fi + easyrsa_openssl req -utf8 -new $algo_opts \ + -keyout "$key_out_tmp" -out "$req_out_tmp" $opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} \ + || die "Failed to generate request" + mv "$key_out_tmp" "$key_out" + mv "$req_out_tmp" "$req_out" + notice "\ +Keypair and certificate request completed. Your files are: +req: $req_out +key: $key_out +" + return 0 +} # => gen_req() + +# common signing backend +sign_req() { + crt_type="$1" + opts="" + req_in="$EASYRSA_PKI/reqs/$2.req" + crt_out="$EASYRSA_PKI/issued/$2.crt" + + # Randomize Serial number + if [ "$EASYRSA_RAND_SN" != "no" ]; + then + i="" + serial="" + check_serial="" + for i in 1 2 3 4 5; do + "$EASYRSA_OPENSSL" rand -hex -out "$EASYRSA_PKI/serial" 16 + serial="$(cat "$EASYRSA_PKI/serial")" + check_serial="$("$EASYRSA_OPENSSL" ca -config "$EASYRSA_SSL_CONF" -status "$serial" 2>&1)" + case "$check_serial" in + *"not present in db"*) break ;; + *) continue ;; + esac + done + fi + + # Support batch by internal caller: + [ "$3" = "batch" ] && EASYRSA_BATCH=1 + + verify_ca_init + + # Check argument sanity: + [ -n "$2" ] || die "\ +Incorrect number of arguments provided to sign-req: +expected 2, got $# (see command help for usage)" + + # Cert type must exist under the EASYRSA_EXT_DIR + [ -r "$EASYRSA_EXT_DIR/$crt_type" ] || die "\ +Unknown cert type '$crt_type'" + + # Request file must exist + [ -f "$req_in" ] || die "\ +No request found for the input: '$2' +Expected to find the request at: $req_in" + + # Confirm input is a cert req + verify_file req "$req_in" || die "\ +The certificate request file is not in a valid X509 request format. +File Path: $req_in" + + # Display the request subject in an easy-to-read format + # Confirm the user wishes to sign this request + confirm "Confirm request details: " "yes" " +You are about to sign the following certificate. +Please check over the details shown below for accuracy. Note that this request +has not been cryptographically verified. Please be sure it came from a trusted +source or that you have verified the request checksum with the sender. + +Request subject, to be signed as a $crt_type certificate for $EASYRSA_CERT_EXPIRE days: + +$(display_dn req "$req_in") +" # => confirm end + + # Generate the extensions file for this cert: + ext_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + { + # Append first any COMMON file (if present) then the cert-type extensions + cat "$EASYRSA_EXT_DIR/COMMON" + cat "$EASYRSA_EXT_DIR/$crt_type" + # copy req extensions + [ "$EASYRSA_CP_EXT" ] && print "copy_extensions = copy" + + # Support a dynamic CA path length when present: + [ "$crt_type" = "ca" ] && [ -n "$EASYRSA_SUBCA_LEN" ] && \ + print "basicConstraints = CA:TRUE, pathlen:$EASYRSA_SUBCA_LEN" + + # Deprecated Netscape extension support, if enabled + if print "$EASYRSA_NS_SUPPORT" | awk_yesno; then + [ -n "$EASYRSA_NS_COMMENT" ] && \ + print "nsComment = \"$EASYRSA_NS_COMMENT\"" + case "$crt_type" in + serverClient) print "nsCertType = serverClient" ;; + server) print "nsCertType = server" ;; + client) print "nsCertType = client" ;; + ca) print "nsCertType = sslCA" ;; + esac + fi + + # If type is server and no subjectAltName was requested, + # add one to the extensions file + if [ "$crt_type" = 'server' ] || [ "$crt_type" = 'serverClient' ]; + then + echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName + if [ $? -ne 0 ]; + then + san=$(display_san req "$req_in") + + if [ -n "$san" ]; + then + print "subjectAltName = $san" + else + default_server_san "$req_in" + fi + fi + fi + + # Add any advanced extensions supplied by env-var: + [ -n "$EASYRSA_EXTRA_EXTS" ] && print "$EASYRSA_EXTRA_EXTS" + + : # needed to keep die from inherting the above test + } > "$ext_tmp" || die "\ +Failed to create temp extension file (bad permissions?) at: +$ext_tmp" + + # sign request + crt_out_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + easyrsa_openssl ca -utf8 -in "$req_in" -out "$crt_out_tmp" \ + -extfile "$ext_tmp" -days "$EASYRSA_CERT_EXPIRE" -batch $opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} \ + || die "signing failed (openssl output above may have more detail)" + mv "$crt_out_tmp" "$crt_out" + rm -f "$ext_tmp" + notice "\ +Certificate created at: $crt_out +" + return 0 +} # => sign_req() + +# common build backend +# used to generate+sign in 1 step +build_full() { + verify_ca_init + + # pull filename base: + [ -n "$2" ] || die "\ +Error: didn't find a file base name as the first argument. +Run easyrsa without commands for usage and commands." + crt_type="$1" name="$2" + req_out="$EASYRSA_PKI/reqs/$2.req" + key_out="$EASYRSA_PKI/private/$2.key" + crt_out="$EASYRSA_PKI/issued/$2.crt" + shift 2 + + # function opts support + req_opts= + while [ -n "$1" ]; do + case "$1" in + nopass) req_opts="$req_opts nopass" ;; + inline) EASYRSA_INLINE=1 ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + # abort on existing req/key/crt files + err_exists="\ +file already exists. Aborting build to avoid overwriting this file. +If you wish to continue, please use a different name or remove the file. +Matching file found at: " + [ -f "$req_out" ] && die "Request $err_exists $req_out" + [ -f "$key_out" ] && die "Key $err_exists $key_out" + [ -f "$crt_out" ] && die "Certificate $err_exists $crt_out" + + # create request + EASYRSA_REQ_CN="$name" + #shellcheck disable=SC2086 + gen_req "$name" batch $req_opts + + # Sign it + ( sign_req "$crt_type" "$name" batch ) || { + rm -f "$req_out" "$key_out" + die "Failed to sign '$name'" + } + + # inline it + if [ $EASYRSA_INLINE ]; then + inline_creds + fi +} # => build_full() + +# Create inline credentials file for this node +inline_creds () +{ + [ -f "$EASYRSA_PKI/$EASYRSA_REQ_CN.creds" ] \ + && die "Inline file exists: $EASYRSA_PKI/$EASYRSA_REQ_CN.creds" + { + printf "%s\n" "# $crt_type: $EASYRSA_REQ_CN" + printf "%s\n" "" + printf "%s\n" "" + cat "$EASYRSA_PKI/ca.crt" + printf "%s\n" "" + printf "%s\n" "" + printf "%s\n" "" + cat "$crt_out" + printf "%s\n" "" + printf "%s\n" "" + printf "%s\n" "" + cat "$key_out" + printf "%s\n" "" + printf "%s\n" "" + } > "$EASYRSA_PKI/$EASYRSA_REQ_CN.creds" +} # => inline_creds () + +# revoke backend +revoke() { + verify_ca_init + + # pull filename base: + [ -n "$1" ] || die "\ +Error: didn't find a file base name as the first argument. +Run easyrsa without commands for usage and command help." + crt_in="$EASYRSA_PKI/issued/$1.crt" + + opts="" + if [ "$2" ]; then + opts="$opts -crl_reason $2" + fi + + verify_file x509 "$crt_in" || die "\ +Unable to revoke as the input file is not a valid certificate. Unexpected +input in file: $crt_in" + + # confirm operation by displaying DN: + confirm "Continue with revocation: " "yes" " +Please confirm you wish to revoke the certificate with the following subject: + +$(display_dn x509 "$crt_in") +" # => confirm end + + # referenced cert must exist: + [ -f "$crt_in" ] || die "\ +Unable to revoke as no certificate was found. Certificate was expected +at: $crt_in" + + # shellcheck disable=SC2086 + easyrsa_openssl ca -utf8 -revoke "$crt_in" ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} $opts || die "\ +Failed to revoke certificate: revocation command failed." + + # move revoked files so we can reissue certificates with the same name + move_revoked "$1" + + notice "\ +IMPORTANT!!! + +Revocation was successful. You must run gen-crl and upload a CRL to your +infrastructure in order to prevent the revoked cert from being accepted. +" # => notice end + return 0 +} #= revoke() + +# move-revoked +# moves revoked certificates to an alternative folder +# allows reissuing certificates with the same name +move_revoked() { + verify_ca_init + + [ -n "$1" ] || die "\ +Error: didn't find a file base name as the first argument. +Run easyrsa without commands for usage and command help." + + crt_in="$EASYRSA_PKI/issued/$1.crt" + key_in="$EASYRSA_PKI/private/$1.key" + req_in="$EASYRSA_PKI/reqs/$1.req" + + verify_file x509 "$crt_in" || die "\ +Unable to move revoked input file. The file is not a valid certificate. Unexpected +input in file: $crt_in" + + if [ -e "$req_in" ] + then + verify_file req "$req_in" || die "\ +Unable to move request. The file is not a valid request. Unexpected +input in file: $req_in" + fi + + # get the serial number of the certificate -> serial=XXXX + cert_serial="$(easyrsa_openssl x509 -in "$crt_in" -noout -serial)" + # remove the serial= part -> we only need the XXXX part + cert_serial=${cert_serial##*=} + + crt_by_serial="$EASYRSA_PKI/certs_by_serial/$cert_serial.pem" + crt_by_serial_revoked="$EASYRSA_PKI/revoked/certs_by_serial/$cert_serial.crt" + key_by_serial_revoked="$EASYRSA_PKI/revoked/private_by_serial/$cert_serial.key" + req_by_serial_revoked="$EASYRSA_PKI/revoked/reqs_by_serial/$cert_serial.req" + + # make sure revoked dirs exist + [ -d "$EASYRSA_PKI/revoked" ] || mkdir "$EASYRSA_PKI/revoked" + [ -d "$EASYRSA_PKI/revoked/certs_by_serial" ] || mkdir "$EASYRSA_PKI/revoked/certs_by_serial" + [ -d "$EASYRSA_PKI/revoked/private_by_serial" ] || mkdir "$EASYRSA_PKI/revoked/private_by_serial" + [ -d "$EASYRSA_PKI/revoked/reqs_by_serial" ] || mkdir "$EASYRSA_PKI/revoked/reqs_by_serial" + + # move crt, key and req file to revoked folders + mv "$crt_in" "$crt_by_serial_revoked" + + # only move the req if we have it + [ -e "$req_in" ] && mv "$req_in" "$req_by_serial_revoked" + + # only move the key if we have it + [ -e "$key_in" ] && mv "$key_in" "$key_by_serial_revoked" + + # move the rest of the files (p12, p7, ...) + # shellcheck disable=SC2231 + for file in $EASYRSA_PKI/private/$1\.??? + do + # get file extension + file_ext="${file##*.}" + + [ -f "$file" ] && mv "$file" "$EASYRSA_PKI/revoked/private_by_serial/$cert_serial.$file_ext" + done + + # remove the dublicate certificate in the certs_by_serial folder + rm "$crt_by_serial" + + return 0 + +} #= move_revoked() + +# renew backend +renew() { + verify_ca_init + + # pull filename base: + [ -n "$1" ] || die "\ +Error: didn't find a file base name as the first argument. +Run easyrsa without commands for usage and command help." + crt_in="$EASYRSA_PKI/issued/$1.crt" + + opts="" + if [ "$2" ]; then + opts="$2" + fi + + verify_file x509 "$crt_in" || die "\ +Unable to renew as the input file is not a valid certificate. Unexpected +input in file: $crt_in" + + # confirm operation by displaying DN: + confirm "Continue with renew: " "yes" " +Please confirm you wish to renew the certificate with the following subject: + +$(display_dn x509 "$crt_in") +" # => confirm end + + # referenced cert must exist: + [ -f "$crt_in" ] || die "\ +Unable to renew as no certificate was found. Certificate was expected +at: $crt_in" + + # Check if old cert is expired or expires within 30 days + expire_date=$( + easyrsa_openssl x509 -in "$crt_in" -noout -enddate | + sed 's/^notAfter=//' + ) + case $(uname 2>/dev/null) in + "Darwin"|*"BSD") + expire_date=$(date -j -f '%b %d %T %Y %Z' "$expire_date" +%s) + allow_renew_date=$(date -j -v"+${EASYRSA_CERT_RENEW}d" +%s) + ;; + *) + # This works on Windows, too, since uname doesn't exist and this is catch-all + expire_date=$(date -d "$expire_date" +%s) + allow_renew_date=$(date -d "+${EASYRSA_CERT_RENEW}day" +%s) + ;; + esac + + [ "$expire_date" -lt "$allow_renew_date" ] || die "\ +Certificate expires in more than $EASYRSA_CERT_RENEW days. +Renewal not allowed." + + # Extract certificate usage from old cert + cert_ext_key_usage=$( + easyrsa_openssl x509 -in "$crt_in" -noout -text | + sed -n "/X509v3 Extended Key Usage:/{n;s/^ *//g;p;}" + ) + case $cert_ext_key_usage in + "TLS Web Client Authentication") + cert_type=client + ;; + "TLS Web Server Authentication") + cert_type=server + ;; + "TLS Web Server Authentication, TLS Web Client Authentication") + cert_type=serverClient + ;; + esac + + # Use SAN from --subject-alt-name if set else use SAN from old cert + echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName || \ + { + san=$( + easyrsa_openssl x509 -in "$crt_in" -noout -text | + sed -n "/X509v3 Subject Alternative Name:/{n;s/IP Address:/IP:/;s/ //g;p;}" + ) + [ -n "$san" ] && export EASYRSA_EXTRA_EXTS="\ +$EASYRSA_EXTRA_EXTS +subjectAltName = $san" + } + + # move renewed files so we can reissue certificate with the same name + # FIXME: Modify revoke() to also work on the renewed certs subdir + move_renewed "$1" + + # renew certificate + # shellcheck disable=SC2086 + build_full $cert_type $1 $opts || die "\ +Failed to renew certificate: renew command failed." + + notice "\ +IMPORTANT!!! + +Renew was successful. +You may want to revoke the old certificate once the new one has been deployed. +" # => notice end + return 0 +} #= renew() + +# move-renewed +# moves renewed certificates to an alternative folder +# allows reissuing certificates with the same name +move_renewed() { + verify_ca_init + + [ -n "$1" ] || die "\ +Error: didn't find a file base name as the first argument. +Run easyrsa without commands for usage and command help." + + crt_in="$EASYRSA_PKI/issued/$1.crt" + key_in="$EASYRSA_PKI/private/$1.key" + req_in="$EASYRSA_PKI/reqs/$1.req" + + verify_file x509 "$crt_in" || die "\ +Unable to move renewed input file. The file is not a valid certificate. Unexpected +input in file: $crt_in" + + if [ -e "$req_in" ] + then + verify_file req "$req_in" || die "\ +Unable to move request. The file is not a valid request. Unexpected +input in file: $req_in" + fi + + # get the serial number of the certificate -> serial=XXXX + cert_serial="$(easyrsa_openssl x509 -in "$crt_in" -noout -serial)" + # remove the serial= part -> we only need the XXXX part + cert_serial=${cert_serial##*=} + + crt_by_serial="$EASYRSA_PKI/certs_by_serial/$cert_serial.pem" + crt_by_serial_renewed="$EASYRSA_PKI/renewed/certs_by_serial/$cert_serial.crt" + key_by_serial_renewed="$EASYRSA_PKI/renewed/private_by_serial/$cert_serial.key" + req_by_serial_renewed="$EASYRSA_PKI/renewed/reqs_by_serial/$cert_serial.req" + + # make sure renewed dirs exist + [ -d "$EASYRSA_PKI/renewed" ] || mkdir "$EASYRSA_PKI/renewed" + [ -d "$EASYRSA_PKI/renewed/certs_by_serial" ] || mkdir "$EASYRSA_PKI/renewed/certs_by_serial" + [ -d "$EASYRSA_PKI/renewed/private_by_serial" ] || mkdir "$EASYRSA_PKI/renewed/private_by_serial" + [ -d "$EASYRSA_PKI/renewed/reqs_by_serial" ] || mkdir "$EASYRSA_PKI/renewed/reqs_by_serial" + + # move crt, key and req file to renewed folders + mv "$crt_in" "$crt_by_serial_renewed" + + # only move the req if we have it + [ -e "$req_in" ] && mv "$req_in" "$req_by_serial_renewed" + + # only move the key if we have it + [ -e "$key_in" ] && mv "$key_in" "$key_by_serial_renewed" + + # move the rest of the files (p12, p7, ...) + # shellcheck disable=SC2231 + for file in $EASYRSA_PKI/private/$1\.??? + do + # get file extension + file_ext="${file##*.}" + + [ -f "$file" ] && mv "$file" "$EASYRSA_PKI/renewed/private_by_serial/$cert_serial.$file_ext" + done + + # remove the duplicate certificate in the certs_by_serial folder + rm "$crt_by_serial" + + return 0 + +} #= move_renewed() + +# gen-crl backend +gen_crl() { + verify_ca_init + + out_file="$EASYRSA_PKI/crl.pem" + out_file_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + easyrsa_openssl ca -utf8 -gencrl -out "$out_file_tmp" ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || die "\ +CRL Generation failed. +" + mv "$out_file_tmp" "$out_file" + + notice "\ +An updated CRL has been created. +CRL file: $out_file +" + return 0 +} # => gen_crl() + +# import-req backend +import_req() { + verify_pki_init + + # pull passed paths + in_req="$1" short_name="$2" + out_req="$EASYRSA_PKI/reqs/$2.req" + + [ -n "$short_name" ] || die "\ +Unable to import: incorrect command syntax. +Run easyrsa without commands for usage and command help." + + verify_file req "$in_req" || die "\ +The input file does not appear to be a certificate request. Aborting import. +File Path: $in_req" + + # destination must not exist + [ -f "$out_req" ] && die "\ +Unable to import the request as the destination file already exists. +Please choose a different name for your imported request file. +Existing file at: $out_req" + + # now import it + cp "$in_req" "$out_req" + + notice "\ +The request has been successfully imported with a short name of: $short_name +You may now use this name to perform signing operations on this request. +" + return 0 +} # => import_req() + +# export pkcs#12 or pkcs#7 +export_pkcs() { + pkcs_type="$1" + shift + + [ -n "$1" ] || die "\ +Unable to export p12: incorrect command syntax. +Run easyrsa without commands for usage and command help." + + short_name="$1" + crt_in="$EASYRSA_PKI/issued/$1.crt" + key_in="$EASYRSA_PKI/private/$1.key" + crt_ca="$EASYRSA_PKI/ca.crt" + shift + + verify_pki_init + + # opts support + want_ca=1 + want_key=1 + want_pass=1 + while [ -n "$1" ]; do + case "$1" in + noca) want_ca="" ;; + nokey) want_key="" ;; + nopass) want_pass="" ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + pkcs_opts= + if [ $want_ca ]; then + verify_file x509 "$crt_ca" || die "\ +Unable to include CA cert in the $pkcs_type output (missing file, or use noca option.) +Missing file expected at: $crt_ca" + pkcs_opts="$pkcs_opts -certfile $crt_ca" + fi + + # input files must exist + verify_file x509 "$crt_in" || die "\ +Unable to export $pkcs_type for short name '$short_name' without the certificate. +Missing cert expected at: $crt_in" + + case "$pkcs_type" in + p12) + pkcs_out="$EASYRSA_PKI/private/$short_name.p12" + + if [ $want_key ]; then + [ -f "$key_in" ] || die "\ +Unable to export p12 for short name '$short_name' without the key +(if you want a p12 without the private key, use nokey option.) +Missing key expected at: $key_in" + else + pkcs_opts="$pkcs_opts -nokeys" + fi + + # export the p12: + # shellcheck disable=SC2086 + easyrsa_openssl pkcs12 -in "$crt_in" -inkey "$key_in" -export \ + -out "$pkcs_out" $pkcs_opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || die "\ +Export of p12 failed: see above for related openssl errors." + ;; + p7) + pkcs_out="$EASYRSA_PKI/issued/$short_name.p7b" + + # export the p7: + # shellcheck disable=SC2086 + easyrsa_openssl crl2pkcs7 -nocrl -certfile "$crt_in" \ + -out "$pkcs_out" $pkcs_opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || die "\ +Export of p7 failed: see above for related openssl errors." + ;; + p8) + if [ -z $want_pass ]; then + pkcs_opts="-nocrypt" + else + pkcs_opts="" + fi + pkcs_out="$EASYRSA_PKI/private/$short_name.p8" + + # export the p8: + # shellcheck disable=SC2086 + easyrsa_openssl pkcs8 -in "$key_in" -topk8 \ + -out "$pkcs_out" $pkcs_opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || die "\ +Export of p8 failed: see above for related openssl errors." + ;; +esac + + notice "\ +Successful export of $pkcs_type file. Your exported file is at the following +location: $pkcs_out +" + return 0 +} # => export_pkcs() + +# set-pass backend +set_pass() { + verify_pki_init + + # key type, supplied internally from frontend command call (rsa/ec) + key_type="$1" + + # values supplied by the user: + raw_file="$2" + file="$EASYRSA_PKI/private/$raw_file.key" + [ -n "$raw_file" ] || die "\ +Missing argument to 'set-$key_type-pass' command: no name/file supplied. +See help output for usage details." + + # parse command options + shift 2 + crypto="-aes256" + while [ -n "$1" ]; do + case "$1" in + nopass) crypto="" ;; + file) file="$raw_file" ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + [ -f "$file" ] || die "\ +Missing private key: expected to find the private key component at: +$file" + + notice "\ +If the key is currently encrypted you must supply the decryption passphrase. +${crypto:+You will then enter a new PEM passphrase for this key.$NL}" + + out_key_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" + easyrsa_openssl "$key_type" -in "$file" -out "$out_key_tmp" $crypto ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || die "\ +Failed to change the private key passphrase. See above for possible openssl +error messages." + + mv "$out_key_tmp" "$file" || die "\ +Failed to change the private key passphrase. See above for error messages." + + notice "Key passphrase successfully changed" + + return 0 +} # => set_pass() + +# update-db backend +update_db() { + verify_ca_init + + easyrsa_openssl ca -utf8 -updatedb ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || die "\ +Failed to perform update-db: see above for related openssl errors." + return 0 +} # => update_db() + +display_san() { + format="$1" path="$2" + + echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName + + if [ $? -eq 0 ]; then + print "$(echo "$EASYRSA_EXTRA_EXTS" | grep subjectAltName | sed 's/^\s*subjectAltName\s*=\s*//')" + else + san=$( + "$EASYRSA_OPENSSL" "$format" -in "$path" -noout -text | + sed -n "/X509v3 Subject Alternative Name:/{n;s/ //g;s/IPAddress:/IP:/g;s/RegisteredID/RID/;p;}" + ) + + [ -n "$san" ] && print "$san" + fi +} + +# display cert DN info on a req/X509, passed by full pathname +display_dn() { + format="$1" path="$2" + print "$("$EASYRSA_OPENSSL" "$format" -in "$path" -noout -subject -nameopt multiline)" + san=$(display_san "$1" "$2") + if [ -n "$san" ]; then + print "" + print "X509v3 Subject Alternative Name:" + print " $san" + fi + +} # => display_dn() + +# generate default SAN from req/X509, passed by full pathname +default_server_san() { + path="$1" + cn=$( + easyrsa_openssl req -in "$path" -noout -subject -nameopt sep_multiline | + awk -F'=' '/^ *CN=/{print $2}' + ) + echo "$cn" | grep -E -q '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' + #shellcheck disable=SC2181 + if [ $? -eq 0 ]; then + print "subjectAltName = IP:$cn" + else + print "subjectAltName = DNS:$cn" + fi +} # => default_server_san() + +# verify a file seems to be a valid req/X509 +verify_file() { + format="$1" + path="$2" + easyrsa_openssl "$format" -in "$path" -noout 2>/dev/null || return 1 + return 0 +} # => verify_file() + +# show-* command backend +# Prints req/cert details in a readable format +show() { + type="$1" + name="$2" + in_file="" + format="" + [ -n "$name" ] || die "\ +Missing expected filename_base argument. +Run easyrsa without commands for usage help." + shift 2 + + # opts support + opts="-${type}opt no_pubkey,no_sigdump" + while [ -n "$1" ]; do + case "$1" in + full) + opts="" + ;; + *) + warn "Ignoring unknown command option: '$1'" + ;; + esac + shift + done + + # Determine cert/req type + if [ "$type" = "cert" ]; then + verify_ca_init + in_file="$EASYRSA_PKI/issued/${name}.crt" + format="x509" + else + verify_pki_init + in_file="$EASYRSA_PKI/reqs/${name}.req" + format="req" + fi + + # Verify file exists and is of the correct type + [ -f "$in_file" ] || die "\ +No such $type file with a basename of '$name' is present. +Expected to find this file at: +$in_file" + verify_file $format "$in_file" || die "\ +This file is not a valid $type file: +$in_file" + + notice "\ +Showing $type details for '$name'. +This file is stored at: +$in_file +" + easyrsa_openssl $format -in "$in_file" -noout -text\ + -nameopt multiline $opts || die "\ +OpenSSL failure to process the input" +} # => show() + +# show-ca command backend +# Prints CA cert details in a readable format +show_ca() { + # opts support + opts="-certopt no_pubkey,no_sigdump" + while [ -n "$1" ]; do + case "$1" in + full) opts= ;; + *) warn "Ignoring unknown command option: '$1'" ;; + esac + shift + done + + verify_ca_init + in_file="$EASYRSA_PKI/ca.crt" + format="x509" + + # Verify file exists and is of the correct type + [ -f "$in_file" ] || die "\ +No such $type file with a basename of '$name' is present. +Expected to find this file at: +$in_file" + verify_file $format "$in_file" || die "\ +This file is not a valid $type file: +$in_file" + + notice "\ +Showing $type details for 'ca'. +This file is stored at: +$in_file +" + easyrsa_openssl $format -in "$in_file" -noout -text\ + -nameopt multiline $opts || die "\ +OpenSSL failure to process the input" +} # => show_ca() + +# vars setup +# Here sourcing of 'vars' if present occurs. If not present, defaults are used +# to support running without a sourced config format +vars_setup() { + # Try to locate a 'vars' file in order of location preference. + # If one is found, source it + vars= + + # set up program path + prog_file="$0" + prog_file2="$(which -- "$prog_file" 2>/dev/null)" && prog_file="$prog_file2" + prog_file2="$(readlink -f "$prog_file" 2>/dev/null)" && prog_file="$prog_file2" + prog_dir="${prog_file%/*}" + prog_vars="${prog_dir}/vars" + # set up PKI path + pki_vars="${EASYRSA_PKI:-$PWD/pki}/vars" + + # command-line path: + if [ ! -z "$EASYRSA_VARS_FILE" ]; then + if [ ! -f "$EASYRSA_VARS_FILE" ]; then + # If the --vars option does not point to a file, show helpful error. + die "The file '$EASYRSA_VARS_FILE' was not found." + fi + vars="$EASYRSA_VARS_FILE" + # PKI location, if present: + elif [ -f "$pki_vars" ]; then + vars="$pki_vars" + # EASYRSA, if defined: + elif [ -n "$EASYRSA" ] && [ -f "$EASYRSA/vars" ]; then + vars="$EASYRSA/vars" + # program location: + elif [ -f "$prog_vars" ]; then + vars="$prog_vars" + fi + + # If a vars file was located, source it + # If $EASYRSA_NO_VARS is defined (not blank) this is skipped + if [ -z "$EASYRSA_NO_VARS" ] && [ -n "$vars" ]; then + if grep -Eq 'EASYRSA_PASSIN|EASYRSA_PASSOUT' "$vars"; then + die "\ +Variable EASYRSA_PASSIN or EASYRSA_PASSOUT has been found in the configuration \ +file. Storing sensitive information in the configuration file is not \ +recommended - please remove it from there before continuing." + fi + #shellcheck disable=SC2034 + EASYRSA_CALLER=1 + # shellcheck disable=SC1090 + . "$vars" + notice "\ +Note: using Easy-RSA configuration from: $vars" + fi + + # Set defaults, preferring existing env-vars if present + set_var EASYRSA "$prog_dir" + set_var EASYRSA_OPENSSL openssl + set_var EASYRSA_PKI "$PWD/pki" + set_var EASYRSA_DN cn_only + set_var EASYRSA_REQ_COUNTRY "US" + set_var EASYRSA_REQ_PROVINCE "California" + set_var EASYRSA_REQ_CITY "San Francisco" + set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" + set_var EASYRSA_REQ_EMAIL me@example.net + set_var EASYRSA_REQ_OU "My Organizational Unit" + set_var EASYRSA_ALGO rsa + set_var EASYRSA_KEY_SIZE 2048 + set_var EASYRSA_CURVE secp384r1 + set_var EASYRSA_EC_DIR "$EASYRSA_PKI/ecparams" + set_var EASYRSA_CA_EXPIRE 3650 + set_var EASYRSA_CERT_EXPIRE 825 # new default of 36 months + set_var EASYRSA_CERT_RENEW 30 + set_var EASYRSA_CRL_DAYS 180 + set_var EASYRSA_NS_SUPPORT no + set_var EASYRSA_NS_COMMENT "Easy-RSA (3.0.8) Generated Certificate" + set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI" + set_var EASYRSA_REQ_CN ChangeMe + set_var EASYRSA_DIGEST sha256 + set_var EASYRSA_SSL_CONF "$EASYRSA_PKI/openssl-easyrsa.cnf" + set_var EASYRSA_SAFE_CONF "$EASYRSA_PKI/safessl-easyrsa.cnf" + set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM" + + # Same as above for the x509-types extensions dir + if [ -d "$EASYRSA_PKI/x509-types" ]; then + set_var EASYRSA_EXT_DIR "$EASYRSA_PKI/x509-types" + else + #TODO: This should be removed. Not really suitable for packaging. + set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types" + fi + + # EASYRSA_ALGO_PARAMS must be set depending on selected algo + if [ "ec" = "$EASYRSA_ALGO" ]; then + EASYRSA_ALGO_PARAMS="$EASYRSA_EC_DIR/${EASYRSA_CURVE}.pem" + elif [ "rsa" = "$EASYRSA_ALGO" ]; then + EASYRSA_ALGO_PARAMS="${EASYRSA_KEY_SIZE}" + elif [ "ed" != "$EASYRSA_ALGO" ]; then + die "Alg '$EASYRSA_ALGO' is invalid: must be 'rsa', 'ec' or 'ed' " + fi + + # Assign value to $EASYRSA_TEMP_DIR_session and work around Windows mktemp bug when parent dir is missing + if [ -z "$EASYRSA_TEMP_DIR_session" ]; then + if [ -d "$EASYRSA_TEMP_DIR" ]; then + EASYRSA_TEMP_DIR_session="$(mktemp -du "$EASYRSA_TEMP_DIR/easy-rsa-$$.XXXXXX")" + else + # If the directory does not exist then we have not run init-pki + mkdir -p "$EASYRSA_TEMP_DIR" || die "Cannot create $EASYRSA_TEMP_DIR (permission?)" + EASYRSA_TEMP_DIR_session="$(mktemp -du "$EASYRSA_TEMP_DIR/easy-rsa-$$.XXXXXX")" + rm -rf "$EASYRSA_TEMP_DIR" + fi + fi + + # Setting OPENSSL_CONF prevents bogus warnings (especially useful on win32) + export OPENSSL_CONF="$EASYRSA_SAFE_CONF" + + # Upgrade to 306: Create $EASYRSA_SSL_CONF if it does not exist but only if $EASYRSA_PKI exists. + if [ ! -f "$EASYRSA_SSL_CONF" ] && [ -f "$EASYRSA/openssl-easyrsa.cnf" ] && [ -d "$EASYRSA_PKI" ]; + then + cp "$EASYRSA/openssl-easyrsa.cnf" "$EASYRSA_SSL_CONF" + easyrsa_openssl makesafeconf + fi + +} # vars_setup() + +# variable assignment by indirection when undefined; merely exports +# the variable when it is already defined (even if currently null) +# Sets $1 as the value contained in $2 and exports (may be blank) +set_var() { + var=$1 + shift + value="$*" + eval "export $var=\"\${$var-$value}\"" +} #=> set_var() + + +############################################################################ +# Upgrade v2 PKI to v3 PKI + +# You can report problems on the normal openvpn support channels: +# -------------------------------------------------------------------------- +# 1. The Openvpn Forum: https://forums.openvpn.net/viewforum.php?f=31 +# 2. The #easyrsa IRC channel at freenode +# 3. Info: https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade +# -------------------------------------------------------------------------- +# + +up23_fail_upgrade () +{ + # Replace die() + unset EASYRSA_BATCH + notice " +============================================================================ +The update has failed but NOTHING has been lost. + +ERROR: $1 +---------------------------------------------------------------------------- + +Further info: +* https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade#ersa-up23-fails + +Easyrsa3 upgrade FAILED +============================================================================ +" + exit 9 +} #=> up23_fail_upgrade () + +up23_verbose () +{ + [ "$VERBOSE" ] || return 0 + printf "%s\n" "$1" +} #=> up23_verbose () + +up23_verify_new_pki () +{ + # Fail now, before any changes are made + + up23_verbose "> Verify DEFAULT NEW PKI does not exist .." + EASYRSA_NEW_PKI="$EASYRSA/pki" + [ -d "$EASYRSA_NEW_PKI" ] \ + && up23_fail_upgrade "DEFAULT NEW PKI exists: $EASYRSA_NEW_PKI" + + up23_verbose "> Verify VERY-SAFE-PKI does not exist .." + EASYRSA_SAFE_PKI="$EASYRSA/VERY-SAFE-PKI" + [ -d "$EASYRSA_SAFE_PKI" ] \ + && up23_fail_upgrade "VERY-SAFE-PKI exists: $EASYRSA_SAFE_PKI" + + up23_verbose "> Verify openssl-easyrsa.cnf does exist .." + EASYRSA_SSL_CNFFILE="$EASYRSA/openssl-easyrsa.cnf" + [ -f "$EASYRSA_SSL_CNFFILE" ] \ + || up23_fail_upgrade "cannot find $EASYRSA_SSL_CNFFILE" + + up23_verbose "> Verify vars.example does exist .." + EASYRSA_VARSV3_EXMP="$EASYRSA/vars.example" + [ -f "$EASYRSA_VARSV3_EXMP" ] \ + || up23_fail_upgrade "cannot find $EASYRSA_VARSV3_EXMP" + + up23_verbose "> OK" + up23_verbose " Initial dirs & files are in a workable state." +} #=> up23_verify_new_pki () + +up23_verify_current_pki () +{ + up23_verbose "> Verify CURRENT PKI vars .." + + # This can probably be improved + EASYRSA_NO_REM="$(grep '^set ' "$EASYRSA_VER2_VARSFILE")" + + # This list may not be complete + # Not required: DH_KEY_SIZE PKCS11_MODULE_PATH PKCS11_PIN + for i in KEY_DIR KEY_SIZE KEY_COUNTRY KEY_PROVINCE \ + KEY_CITY KEY_ORG KEY_EMAIL KEY_CN KEY_NAME KEY_OU + do + # Effectively, source the v2 vars file + UNIQUE="set $i" + KEY_grep="$(printf "%s\n" "$EASYRSA_NO_REM" | grep "$UNIQUE")" + KEY_value="${KEY_grep##*=}" + set_var $i "$KEY_value" + done + + [ -d "$KEY_DIR" ] || up23_fail_upgrade "Cannot find CURRENT PKI KEY_DIR: $KEY_DIR" + + up23_verbose "> OK" + up23_verbose " Current CURRENT PKI vars uses PKI in: $KEY_DIR" +} #=> up23_verify_current_pki () + +up23_verify_current_ca () +{ + up23_verbose "> Find CA .." + # $KEY_DIR is assigned in up23_verify_current_pki () + [ -f "$KEY_DIR/ca.crt" ] \ + || up23_fail_upgrade "Cannot find current ca.crt: $KEY_DIR/ca.crt" + up23_verbose "> OK" + + # If CA is already verified then return + in_file="$KEY_DIR/ca.crt" + [ "$CURRENT_CA_IS_VERIFIED" = "$in_file" ] && return 0 + format="x509" + + # Current CA is unverified + # Extract the current CA details + CA_SUBJECT="$(easyrsa_openssl $format -in "$in_file" -subject -noout -nameopt multiline)" + + # Extract individual elements + CA_countryName="$(printf "%s\n" "$CA_SUBJECT" \ + | grep countryName | sed "s\`^.*=\ \`\`g")" + CA_stateOrProvinceName="$(printf "%s\n" "$CA_SUBJECT" \ + | grep stateOrProvinceName | sed "s\`^.*=\ \`\`g")" + CA_localityName="$(printf "%s\n" "$CA_SUBJECT" \ + | grep localityName | sed "s\`^.*=\ \`\`g")" + CA_organizationName="$(printf "%s\n" "$CA_SUBJECT" \ + | grep organizationName | sed "s\`^.*=\ \`\`g")" + CA_organizationalUnitName="$(printf "%s\n" "$CA_SUBJECT" \ + | grep organizationalUnitName | sed "s\`^.*=\ \`\`g")" + CA_emailAddress="$(printf "%s\n" "$CA_SUBJECT" \ + | grep emailAddress | sed "s\`^.*=\ \`\`g")" + + # Match the current CA elements to the vars file settings + CA_vars_match=1 + [ "$CA_countryName" = "$KEY_COUNTRY" ] || CA_vars_match=0 + [ "$CA_stateOrProvinceName" = "$KEY_PROVINCE" ] || CA_vars_match=0 + [ "$CA_localityName" = "$KEY_CITY" ] || CA_vars_match=0 + [ "$CA_organizationName" = "$KEY_ORG" ] || CA_vars_match=0 + [ "$CA_organizationalUnitName" = "$KEY_OU" ] || CA_vars_match=0 + [ "$CA_emailAddress" = "$KEY_EMAIL" ] || CA_vars_match=0 + + if [ "$CA_vars_match" -eq 1 ] + then + CURRENT_CA_IS_VERIFIED="partially" + else + up23_fail_upgrade "CA certificate does not match vars file settings" + fi + + opts="-certopt no_pubkey,no_sigdump" + if [ ! "$EASYRSA_BATCH" ] + then + up23_show_current_ca + elif [ "$VERBOSE" ] + then + up23_show_current_ca + fi + confirm "* Confirm CA shown above is correct: " "yes" \ + "Found current CA at: $KEY_DIR/ca.crt" + CURRENT_CA_IS_VERIFIED="$in_file" +} #=> up23_verify_current_ca () + +up23_show_current_ca () +{ + printf "%s\n" "-------------------------------------------------------------------------" + # $opts is always set here + # shellcheck disable=SC2086 + easyrsa_openssl $format -in "$in_file" -noout -text\ + -nameopt multiline $opts || die "\ + OpenSSL failure to process the input CA certificate: $in_file" + printf "%s\n" "-------------------------------------------------------------------------" +} #=> up23_show_current_ca () + +up23_backup_current_pki () +{ + up23_verbose "> Backup current PKI .." + + mkdir -p "$EASYRSA_SAFE_PKI" \ + || up23_fail_upgrade "Failed to create safe PKI dir: $EASYRSA_SAFE_PKI" + + cp -r "$KEY_DIR" "$EASYRSA_SAFE_PKI" \ + || up23_fail_upgrade "Failed to copy $KEY_DIR to $EASYRSA_SAFE_PKI" + + # EASYRSA_VER2_VARSFILE is either version 2 *nix ./vars or Win vars.bat + cp "$EASYRSA_VER2_VARSFILE" "$EASYRSA_SAFE_PKI" \ + || up23_fail_upgrade "Failed to copy $EASYRSA_VER2_VARSFILE to EASYRSA_SAFE_PKI" + + up23_verbose "> OK" + up23_verbose " Current PKI backup created in: $EASYRSA_SAFE_PKI" +} #=> up23_backup_current_pki () + +up23_create_new_pki () +{ + # Dirs: renewed and revoked are created when used. + up23_verbose "> Create NEW PKI .." + up23_verbose ">> Create NEW PKI dirs .." + for i in private reqs issued certs_by_serial + do + mkdir -p "$EASYRSA_PKI/$i" \ + || up23_fail_upgrade "Failed to Create NEW PKI dir: $EASYRSA_PKI/$i" + done + up23_verbose ">> OK" + + up23_verbose ">> Copy database to NEW PKI .." + # Failure for these is not optional + # Files ignored: index.txt.old serial.old + for i in index.txt serial ca.crt index.txt.attr + do + cp "$KEY_DIR/$i" "$EASYRSA_PKI" \ + || up23_fail_upgrade "Failed to copy $KEY_DIR/$i to $EASYRSA_PKI" + done + up23_verbose ">> OK" + + up23_verbose ">> Copy current PKI to NEW PKI .." + for i in "csr.reqs" "pem.certs_by_serial" "crt.issued" "key.private" \ + "p12.private" "p8.private" "p7b.issued" + do + FILE_EXT="${i%%.*}" + DEST_DIR="${i##*.}" + if ls "$KEY_DIR/"*".$FILE_EXT" > /dev/null 2>&1; then + cp "$KEY_DIR/"*".$FILE_EXT" "$EASYRSA_PKI/$DEST_DIR" \ + || up23_fail_upgrade "Failed to copy .$FILE_EXT" + else + up23_verbose " Note: No .$FILE_EXT files found" + fi + done + up23_verbose ">> OK" + up23_verbose "> OK" + + # Todo: CRL - Or generate a new CRL on completion + up23_verbose " New PKI created in: $EASYRSA_PKI" +} #=> up23_create_new_pki () + +up23_upgrade_ca () +{ + [ -d "$EASYRSA_PKI" ] || return 0 + up23_verbose "> Confirm that index.txt.attr exists and 'unique_subject = no'" + if [ -f "$EASYRSA_PKI/index.txt.attr" ] + then + if grep -q 'unique_subject = no' "$EASYRSA_PKI/index.txt.attr" + then + # If index.txt.attr exists and "unique_suject = no" then do nothing + return 0 + fi + else + # If index.txt.attr does not exists then do nothing + return 0 + fi + + # Otherwise this is required for all easyrsa v3 + #confirm "Set 'unique_subject = no' in index.txt.attr for your current CA: " \ + #"yes" "This version of easyrsa requires that 'unique_subject = no' is set correctly" + + printf "%s\n" "unique_subject = no" > "$EASYRSA_PKI/index.txt.attr" + up23_verbose "> OK" + up23_verbose " Upgraded index.txt.attr to v306+" +} #=> up23_upgrade_index_txt_attr () + +up23_create_openssl_cnf () +{ + up23_verbose "> OpenSSL config .." + EASYRSA_PKI_SSL_CNFFILE="$EASYRSA_PKI/openssl-easyrsa.cnf" + EASYRSA_PKI_SAFE_CNFFILE="$EASYRSA_PKI/safessl-easyrsa.cnf" + cp "$EASYRSA_SSL_CNFFILE" "$EASYRSA_PKI_SSL_CNFFILE" \ + || up23_fail_upgrade "create $EASYRSA_PKI_SSL_CNFFILE" + up23_verbose "> OK" + up23_verbose " New OpenSSL config file created in: $EASYRSA_PKI_SSL_CNFFILE" + + # Create $EASYRSA_PKI/safessl-easyrsa.cnf + easyrsa_openssl makesafeconf + if [ -f "$EASYRSA_PKI_SAFE_CNFFILE" ] + then + up23_verbose " New SafeSSL config file created in: $EASYRSA_PKI_SAFE_CNFFILE" + else + up23_verbose " FAILED to create New SafeSSL config file in: $EASYRSA_PKI_SAFE_CNFFILE" + fi +} #=> up23_create_openssl_cnf () + +up23_move_easyrsa2_programs () +{ + # These files may not exist here + up23_verbose "> Move easyrsa2 programs to SAFE PKI .." + for i in build-ca build-dh build-inter build-key build-key-pass \ + build-key-pkcs12 build-key-server build-req build-req-pass \ + clean-all inherit-inter list-crl pkitool revoke-full sign-req \ + whichopensslcnf build-ca-pass build-key-server-pass init-config \ + make-crl revoke-crt openssl-0.9.6.cnf openssl-0.9.8.cnf \ + openssl-1.0.0.cnf openssl.cnf README.txt index.txt.start \ + vars.bat.sample serial.start + do + # Although unlikely, both files could exist + # EG: ./build-ca and ./build-ca.bat + NIX_FILE="$EASYRSA/$i" + WIN_FILE="$EASYRSA/$i.bat" + if [ -f "$NIX_FILE" ] + then + cp "$NIX_FILE" "$EASYRSA_SAFE_PKI" \ + || up23_fail_upgrade "copy $NIX_FILE $EASYRSA_SAFE_PKI" + fi + + if [ -f "$WIN_FILE" ] + then + cp "$WIN_FILE" "$EASYRSA_SAFE_PKI" \ + || up23_fail_upgrade "copy $WIN_FILE $EASYRSA_SAFE_PKI" + fi + + if [ ! -f "$NIX_FILE" ] && [ ! -f "$WIN_FILE" ] + then + up23_verbose "File does not exist, ignoring: $i(.bat)" + fi + + # These files are not removed on TEST run + [ "$NOSAVE" -eq 1 ] && rm -f "$NIX_FILE" "$WIN_FILE" + done + + up23_verbose "> OK" + up23_verbose " Easyrsa2 programs successfully moved to: $EASYRSA_SAFE_PKI" +} #=> up23_move_easyrsa2_programs () + +up23_build_v3_vars () +{ + up23_verbose "> Build v3 vars file .." + + EASYRSA_EXT="easyrsa-upgrade-23" + EASYRSA_VARSV2_TMP="$EASYRSA/vars-v2.tmp.$EASYRSA_EXT" + rm -f "$EASYRSA_VARSV2_TMP" + EASYRSA_VARSV3_TMP="$EASYRSA/vars-v3.tmp.$EASYRSA_EXT" + rm -f "$EASYRSA_VARSV3_TMP" + EASYRSA_VARSV3_NEW="$EASYRSA/vars-v3.new.$EASYRSA_EXT" + rm -f "$EASYRSA_VARSV3_NEW" + EASYRSA_VARSV3_WRN="$EASYRSA/vars-v3.wrn.$EASYRSA_EXT" + rm -f "$EASYRSA_VARSV3_WRN" + + printf "%s\n" "\ +########################++++++++++######################### +### ### +### WARNING: THIS FILE WAS AUTOMATICALLY GENERATED ### +### ALL SETTINGS ARE AT THE END OF THE FILE ### +### ### +########################++++++++++######################### + +" > "$EASYRSA_VARSV3_WRN" || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_WRN" + + # Create vars v3 temp file from sourced vars v2 key variables + { + printf "%s\n" "set_var EASYRSA_KEY_SIZE $KEY_SIZE" + printf "%s\n" "set_var EASYRSA_REQ_COUNTRY \"$KEY_COUNTRY\"" + printf "%s\n" "set_var EASYRSA_REQ_PROVINCE \"$KEY_PROVINCE\"" + printf "%s\n" "set_var EASYRSA_REQ_CITY \"$KEY_CITY\"" + printf "%s\n" "set_var EASYRSA_REQ_ORG \"$KEY_ORG\"" + printf "%s\n" "set_var EASYRSA_REQ_EMAIL \"$KEY_EMAIL\"" + printf "%s\n" "set_var EASYRSA_REQ_OU \"$KEY_OU\"" + printf "%s\n" 'set_var EASYRSA_NS_SUPPORT "yes"' + printf "%s\n" 'set_var EASYRSA_DN "org"' + printf "%s\n" 'set_var EASYRSA_RAND_SN "no"' + printf "%s\n" "" + } > "$EASYRSA_VARSV3_TMP" \ + || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_TMP" + + # cat temp files into new v3 vars + cat "$EASYRSA_VARSV3_WRN" "$EASYRSA_VARSV3_EXMP" "$EASYRSA_VARSV3_TMP" \ + > "$EASYRSA_VARSV3_NEW" \ + || up23_fail_upgrade "Failed to create $EASYRSA_VARSV3_NEW" + + # This file must be created and restored at the end of TEST + # for the REAL update to to succeed + EASYRSA_VARS_LIVEBKP="$EASYRSA_TARGET_VARSFILE.livebackup" + cp "$EASYRSA_VER2_VARSFILE" "$EASYRSA_VARS_LIVEBKP" \ + || up23_fail_upgrade "Failed to create $EASYRSA_VARS_LIVEBKP" + rm -f "$EASYRSA_VER2_VARSFILE" + + # "$EASYRSA_TARGET_VARSFILE" is always $EASYRSA/vars + cp "$EASYRSA_VARSV3_NEW" "$EASYRSA_TARGET_VARSFILE" \ + || up23_fail_upgrade "copy $EASYRSA_VARSV3_NEW to $EASYRSA_TARGET_VARSFILE" + + # Delete temp files + rm -f "$EASYRSA_VARSV2_TMP" "$EASYRSA_VARSV3_TMP" \ + "$EASYRSA_VARSV3_NEW" "$EASYRSA_VARSV3_WRN" + + up23_verbose "> OK" + up23_verbose " New v3 vars file created in: $EASYRSA_TARGET_VARSFILE" +} #=> up23_build_v3_vars () + +up23_do_upgrade_23 () +{ + up23_verbose "============================================================================" + up23_verbose "Begin ** $1 ** upgrade process .." + up23_verbose "" + up23_verbose "Easyrsa upgrade version: $EASYRSA_UPGRADE_23" + up23_verbose "" + + up23_verify_new_pki + up23_verify_current_pki + up23_verify_current_ca + up23_backup_current_pki + up23_create_new_pki + up23_upgrade_ca + up23_move_easyrsa2_programs + up23_build_v3_vars + up23_create_openssl_cnf + + if [ "$NOSAVE" -eq 0 ] + then + # Must stay in this order + # New created dirs: EASYRSA_NEW_PKI and EASYRSA_SAFE_PKI + rm -rf "$EASYRSA_NEW_PKI" + rm -rf "$EASYRSA_SAFE_PKI" + # EASYRSA_TARGET_VARSFILE is always the new created v3 vars + # Need to know if this fails + rm "$EASYRSA_TARGET_VARSFILE" \ + || up23_fail_upgrade "remove new vars file: $EASYRSA_TARGET_VARSFILE" + # EASYRSA_VER2_VARSFILE is either v2 *nix ./vars or Win vars.bat + # Need this dance because v2 vars is same name as v3 vars above + cp "$EASYRSA_VARS_LIVEBKP" "$EASYRSA_VER2_VARSFILE" + fi + rm -f "$EASYRSA_VARS_LIVEBKP" +} #= up23_do_upgrade_23 () + +up23_manage_upgrade_23 () +{ + EASYRSA_UPGRADE_VERSION="v1.0a (2020/01/08)" + EASYRSA_UPGRADE_TYPE="$1" + EASYRSA_FOUND_VARS=0 + + # Verify all existing versions of vars/vars.bat + if [ -f "$vars" ] + then + if grep -q 'Complain if a user tries to do this:' "$vars" + then + EASYRSA_FOUND_VARS=1 + EASYRSA_VARS_IS_VER3=1 + fi + + # Easyrsa v3 does not use NOR allow use of `export`. + if grep -q 'export' "$vars" + then + EASYRSA_FOUND_VARS=1 + EASYRSA_VARS_IS_VER2=1 + EASYRSA_VER2_VARSFILE="$vars" + EASYRSA_TARGET_VARSFILE="$vars" + fi + fi + + if [ -f "$EASYRSA/vars.bat" ] + then + EASYRSA_FOUND_VARS=1 + EASYRSA_VARS_IS_WIN2=1 + EASYRSA_VER2_VARSFILE="$EASYRSA/vars.bat" + EASYRSA_TARGET_VARSFILE="$EASYRSA/vars" + fi + + if [ $EASYRSA_FOUND_VARS -ne 1 ]; + then + die echo "vars file not found" + fi + + # Only allow specific vars/vars.bat to exist + if [ "$EASYRSA_VARS_IS_VER3" ] && [ "$EASYRSA_VARS_IS_VER2" ] + then + die "Verify your current vars file, v3 cannot use 'export'." + fi + + if [ "$EASYRSA_VARS_IS_VER3" ] && [ "$EASYRSA_VARS_IS_WIN2" ] + then + die "Verify your current vars/vars.bat file, cannot have both." + fi + + if [ "$EASYRSA_VARS_IS_VER2" ] && [ "$EASYRSA_VARS_IS_WIN2" ] + then + die "Verify your current vars/vars.bat file, cannot have both." + fi + + # Die on invalid upgrade type or environment + if [ "$EASYRSA_UPGRADE_TYPE" = "ca" ] + then + if [ "$EASYRSA_VARS_IS_VER3" ] + then + # v3 ensure index.txt.attr "unique_subject = no" + up23_upgrade_ca + unset EASYRSA_BATCH + notice "Your CA is fully up to date." + return 0 + else + die "Only v3 PKI CA can be upgraded." + fi + fi + + if [ "$EASYRSA_UPGRADE_TYPE" = "pki" ] + then + if [ "$EASYRSA_VARS_IS_VER3" ] + then + unset EASYRSA_BATCH + notice "Your PKI is fully up to date." + return 0 + fi + else + die "upgrade type must be 'pki' or 'ca'." + fi + + # PKI is potentially suitable for upgrade + + warn " +========================================================================= + + * WARNING * + +Found settings from EasyRSA-v2 which are not compatible with EasyRSA-v3. +Before you can continue, EasyRSA must upgrade your settings and PKI. +* Found EASYRSA and vars file: + $EASYRSA + $EASYRSA_VER2_VARSFILE : + +Further info: +* https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade + +Easyrsa upgrade version: $EASYRSA_UPGRADE_VERSION +========================================================================= +" + +# Test upgrade + + NOSAVE=0 + + confirm "* EasyRSA **TEST** upgrade (Changes will NOT be written): " "yes" " +This upgrade will TEST that the upgrade works BEFORE making any changes." + + up23_do_upgrade_23 "TEST" + + notice " +========================================================================= + + * NOTICE * + +EasyRSA upgrade **TEST** has successfully completed. +" +# Upgrade for REAL + + NOSAVE=1 + + confirm "* EasyRSA **REAL** upgrade (Changes WILL be written): " "yes" " +========================================================================= + + * WARNING * + +Run REAL upgrade: Answer yes (Once completed you will have a version 3 PKI) +Terminate upgrade: Answer no (No changes have been made to your current PKI) +" + + confirm "* Confirm **REAL** upgrade (Changes will be written): " "yes" " +========================================================================= + + * SECOND WARNING * + +This upgrade will permanently write changes to your PKI ! +(With full backup backout) +" + up23_do_upgrade_23 "REAL" + + notice " +========================================================================= + + * NOTICE * + +Your settings and PKI have been successfully upgraded to EasyRSA version3 + +A backup of your current PKI is here: + $EASYRSA_SAFE_PKI + + * IMPORTANT NOTICE * + +1. YOU MUST VERIFY THAT YOUR NEW ./vars FILE IS SETUP CORRECTLY +2. IF YOU ARE USING WINDOWS YOU MUST ENSURE THAT openssl IS CORRECTLY DEFINED + IN ./vars (example follows) + + # + # This sample is in Windows syntax -- edit it for your path if not using PATH: + # set_var EASYRSA_OPENSSL \"C:/Program Files/OpenSSL-Win32/bin/openssl.exe\" + # + # Alternate location (Note: Forward slash '/' is correct for Windpws): + # set_var EASYRSA_OPENSSL \"C:/Program Files/Openvpn/bin/openssl.exe\" + # + +3. Finally, you can verify that easyrsa works by using these two commands: + ./easyrsa show-ca (Verify that your CA is intact and correct) + ./easyrsa gen-crl ((re)-generate a CRL file) + +Further info: +* https://community.openvpn.net/openvpn/wiki/easyrsa-upgrade" + up23_verbose " + * UPGRADE COMPLETED SUCCESSFULLY * +" + +return 0 + +} # => up23_manage_upgrade_23 () + +print_version() +{ + cat < print_version () + + +######################################## +# Invocation entry point: + +NL=' +' + +# Be secure with a restrictive umask +[ -z "$EASYRSA_NO_UMASK" ] && umask 077 + +# Parse options +while :; do + # Separate option from value: + opt="${1%%=*}" + val="${1#*=}" + empty_ok="" # Empty values are not allowed unless excepted + + case "$opt" in + --days) + export EASYRSA_CERT_EXPIRE="$val" + export EASYRSA_CA_EXPIRE="$val" + export EASYRSA_CRL_DAYS="$val" + ;; + --pki-dir) + export EASYRSA_PKI="$val" ;; + --use-algo) + export EASYRSA_ALGO="$val" ;; + --keysize) + export EASYRSA_KEY_SIZE="$val" ;; + --curve) + export EASYRSA_CURVE="$val" ;; + --dn-mode) + export EASYRSA_DN="$val" ;; + --req-cn) + export EASYRSA_REQ_CN="$val" ;; + --digest) + export EASYRSA_DIGEST="$val" ;; + --req-c) + empty_ok=1 + export EASYRSA_REQ_COUNTRY="$val" ;; + --req-st) + empty_ok=1 + export EASYRSA_REQ_PROVINCE="$val" ;; + --req-city) + empty_ok=1 + export EASYRSA_REQ_CITY="$val" ;; + --req-org) + empty_ok=1 + export EASYRSA_REQ_ORG="$val" ;; + --req-email) + empty_ok=1 + export EASYRSA_REQ_EMAIL="$val" ;; + --req-ou) + empty_ok=1 + export EASYRSA_REQ_OU="$val" ;; + --ns-cert) + export EASYRSA_NS_SUPPORT="$val" ;; + --ns-comment) + empty_ok=1 + export EASYRSA_NS_COMMENT="$val" ;; + --batch) + empty_ok=1 + export EASYRSA_BATCH=1 ;; + --passin) + export EASYRSA_PASSIN="$val";; + --passout) + export EASYRSA_PASSOUT="$val";; + --subca-len) + export EASYRSA_SUBCA_LEN="$val" ;; + --vars) + export EASYRSA_VARS_FILE="$val" ;; + --copy-ext) + empty_ok=1 + export EASYRSA_CP_EXT=1 ;; + --subject-alt-name) + export EASYRSA_EXTRA_EXTS="\ +$EASYRSA_EXTRA_EXTS +subjectAltName = $val" ;; + --version) + print_version + ;; + *) + break ;; + esac + + # fatal error when no value was provided + if [ ! $empty_ok ] && { [ "$val" = "$1" ] || [ -z "$val" ]; }; then + die "Missing value to option: $opt" + fi + + shift +done + +# Intelligent env-var detection and auto-loading: +vars_setup + +# Register cleanup on EXIT +trap "cleanup" EXIT +# When SIGHUP, SIGINT, SIGQUIT, SIGABRT and SIGTERM, +# explicitly exit to signal EXIT (non-bash shells) +trap "exit 1" 1 +trap "exit 2" 2 +trap "exit 3" 3 +trap "exit 6" 6 +trap "exit 14" 15 + +# Upgrade: EasyRSA v2.x to EasyRSA v3.x +# Upgrade: EasyRSA < v3.0.6 to v3.0.6+ +#up23_manage_upgrade_23 + +# determine how we were called, then hand off to the function responsible +cmd="$1" +[ -n "$1" ] && shift # scrape off command +case "$cmd" in + init-pki|clean-all) + init_pki "$@" + ;; + build-ca) + build_ca "$@" + ;; + gen-dh) + gen_dh + ;; + gen-req) + gen_req "$@" + ;; + sign|sign-req) + sign_req "$@" + ;; + build-client-full) + build_full client "$@" + ;; + build-server-full) + build_full server "$@" + ;; + build-serverClient-full) + build_full serverClient "$@" + ;; + gen-crl) + gen_crl + ;; + revoke) + revoke "$@" + ;; + renew) + renew "$@" + ;; + import-req) + import_req "$@" + ;; + export-p12) + export_pkcs p12 "$@" + ;; + export-p7) + export_pkcs p7 "$@" + ;; + export-p8) + export_pkcs p8 "$@" + ;; + set-rsa-pass) + set_pass rsa "$@" + ;; + set-ec-pass) + set_pass ec "$@" + ;; + update-db) + update_db + ;; + show-req) + show req "$@" + ;; + show-cert) + show cert "$@" + ;; + show-ca) + show_ca "$@" + ;; + upgrade) + up23_manage_upgrade_23 "$@" + ;; + ""|help|-h|--help|--usage) + cmd_help "$1" + exit 0 + ;; + version) + print_version + ;; + *) + die "Unknown command '$cmd'. Run without commands for usage help." + ;; +esac + +# vim: ft=sh nu ai sw=8 ts=8 noet diff --git a/deploy/data/windows/easyrsa/openssl-easyrsa.cnf b/deploy/data/windows/easyrsa/openssl-easyrsa.cnf new file mode 100644 index 00000000..5c4fc79e --- /dev/null +++ b/deploy/data/windows/easyrsa/openssl-easyrsa.cnf @@ -0,0 +1,138 @@ +# For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = $ENV::EASYRSA_PKI # Where everything is kept +certs = $dir # Where the issued certs are kept +crl_dir = $dir # Where the issued crl are kept +database = $dir/index.txt # database index file. +new_certs_dir = $dir/certs_by_serial # default place for new certs. + +certificate = $dir/ca.crt # The CA certificate +serial = $dir/serial # The current serial number +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/ca.key # The private key +RANDFILE = $dir/.rand # private random number file + +x509_extensions = basic_exts # The extensions to add to the cert + +# This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA +# is designed for will. In return, we get the Issuer attached to CRLs. +crl_extensions = crl_ext + +default_days = $ENV::EASYRSA_CERT_EXPIRE # how long to certify for +default_crl_days= $ENV::EASYRSA_CRL_DAYS # how long before next CRL +default_md = $ENV::EASYRSA_DIGEST # use public key default MD +preserve = no # keep passed DN ordering + +# This allows to renew certificates which have not been revoked +unique_subject = no + +# A few different ways of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_anything + +# For the 'anything' policy, which defines allowed DN fields +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +name = optional +emailAddress = optional + +#################################################################### +# Easy-RSA request handling +# We key off $DN_MODE to determine how to format the DN +[ req ] +default_bits = $ENV::EASYRSA_KEY_SIZE +default_keyfile = privkey.pem +default_md = $ENV::EASYRSA_DIGEST +distinguished_name = $ENV::EASYRSA_DN +x509_extensions = easyrsa_ca # The extensions to add to the self signed cert + +# A placeholder to handle the $EXTRA_EXTS feature: +#%EXTRA_EXTS% # Do NOT remove or change this line as $EXTRA_EXTS support requires it + +#################################################################### +# Easy-RSA DN (Subject) handling + +# Easy-RSA DN for cn_only support: +[ cn_only ] +commonName = Common Name (eg: your user, host, or server name) +commonName_max = 64 +commonName_default = $ENV::EASYRSA_REQ_CN + +# Easy-RSA DN for org support: +[ org ] +countryName = Country Name (2 letter code) +countryName_default = $ENV::EASYRSA_REQ_COUNTRY +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = $ENV::EASYRSA_REQ_PROVINCE + +localityName = Locality Name (eg, city) +localityName_default = $ENV::EASYRSA_REQ_CITY + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = $ENV::EASYRSA_REQ_ORG + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = $ENV::EASYRSA_REQ_OU + +commonName = Common Name (eg: your user, host, or server name) +commonName_max = 64 +commonName_default = $ENV::EASYRSA_REQ_CN + +emailAddress = Email Address +emailAddress_default = $ENV::EASYRSA_REQ_EMAIL +emailAddress_max = 64 + +#################################################################### +# Easy-RSA cert extension handling + +# This section is effectively unused as the main script sets extensions +# dynamically. This core section is left to support the odd usecase where +# a user calls openssl directly. +[ basic_exts ] +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always + +# The Easy-RSA CA extensions +[ easyrsa_ca ] + +# PKIX recommendations: + +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always + +# This could be marked critical, but it's nice to support reading by any +# broken clients who attempt to do so. +basicConstraints = CA:true + +# Limit key usage to CA tasks. If you really want to use the generated pair as +# a self-signed cert, comment this out. +keyUsage = cRLSign, keyCertSign + +# nsCertType omitted by default. Let's try to let the deprecated stuff die. +# nsCertType = sslCA + +# CRL extensions. +[ crl_ext ] + +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + diff --git a/deploy/data/windows/easyrsa/vars b/deploy/data/windows/easyrsa/vars new file mode 100644 index 00000000..28be4fd3 --- /dev/null +++ b/deploy/data/windows/easyrsa/vars @@ -0,0 +1,221 @@ +# Easy-RSA 3 parameter settings + +# NOTE: If you installed Easy-RSA from your distro's package manager, don't edit +# this file in place -- instead, you should copy the entire easy-rsa directory +# to another location so future upgrades don't wipe out your changes. + +# HOW TO USE THIS FILE +# +# vars.example contains built-in examples to Easy-RSA settings. You MUST name +# this file 'vars' if you want it to be used as a configuration file. If you do +# not, it WILL NOT be automatically read when you call easyrsa commands. +# +# It is not necessary to use this config file unless you wish to change +# operational defaults. These defaults should be fine for many uses without the +# need to copy and edit the 'vars' file. +# +# All of the editable settings are shown commented and start with the command +# 'set_var' -- this means any set_var command that is uncommented has been +# modified by the user. If you're happy with a default, there is no need to +# define the value to its default. + +# NOTES FOR WINDOWS USERS +# +# Paths for Windows *MUST* use forward slashes, or optionally double-escaped +# backslashes (single forward slashes are recommended.) This means your path to +# the openssl binary might look like this: +# "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" + +# A little housekeeping: DON'T EDIT THIS SECTION +# +# Easy-RSA 3.x doesn't source into the environment directly. +# Complain if a user tries to do this: +if [ -z "$EASYRSA_CALLER" ]; then + echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2 + echo "This is no longer necessary and is disallowed. See the section called" >&2 + echo "'How to use this file' near the top comments for more details." >&2 + return 1 +fi + +# DO YOUR EDITS BELOW THIS POINT + +# This variable is used as the base location of configuration files needed by +# easyrsa. More specific variables for specific files (e.g., EASYRSA_SSL_CONF) +# may override this default. +# +# The default value of this variable is the location of the easyrsa script +# itself, which is also where the configuration files are located in the +# easy-rsa tree. + +#set_var EASYRSA "${0%/*}" + +# If your OpenSSL command is not in the system PATH, you will need to define the +# path to it here. Normally this means a full path to the executable, otherwise +# you could have left it undefined here and the shown default would be used. +# +# Windows users, remember to use paths with forward-slashes (or escaped +# back-slashes.) Windows users should declare the full path to the openssl +# binary here if it is not in their system PATH. + +#set_var EASYRSA_OPENSSL "openssl" +# +# This sample is in Windows syntax -- edit it for your path if not using PATH: +#set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" + +# Edit this variable to point to your soon-to-be-created key directory. By +# default, this will be "$PWD/pki" (i.e. the "pki" subdirectory of the +# directory you are currently in). +# +# WARNING: init-pki will do a rm -rf on this directory so make sure you define +# it correctly! (Interactive mode will prompt before acting.) + +#set_var EASYRSA_PKI "$PWD/pki" + +# Define directory for temporary subdirectories. + +#set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI" + +# Define X509 DN mode. +# This is used to adjust what elements are included in the Subject field as the DN +# (this is the "Distinguished Name.") +# Note that in cn_only mode the Organizational fields further below aren't used. +# +# Choices are: +# cn_only - use just a CN value +# org - use the "traditional" Country/Province/City/Org/OU/email/CN format + +#set_var EASYRSA_DN "cn_only" + +# Organizational fields (used with 'org' mode and ignored in 'cn_only' mode.) +# These are the default values for fields which will be placed in the +# certificate. Don't leave any of these fields blank, although interactively +# you may omit any specific field by typing the "." symbol (not valid for +# email.) + +set_var EASYRSA_REQ_COUNTRY "US" +set_var EASYRSA_REQ_PROVINCE "California" +set_var EASYRSA_REQ_CITY "San Francisco" +set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" +set_var EASYRSA_REQ_EMAIL "me@example.net" +set_var EASYRSA_REQ_OU "My Organizational Unit" + +# Choose a size in bits for your keypairs. The recommended value is 2048. Using +# 2048-bit keys is considered more than sufficient for many years into the +# future. Larger keysizes will slow down TLS negotiation and make key/DH param +# generation take much longer. Values up to 4096 should be accepted by most +# software. Only used when the crypto alg is rsa (see below.) + +#set_var EASYRSA_KEY_SIZE 2048 + +# The default crypto mode is rsa; ec can enable elliptic curve support. +# Note that not all software supports ECC, so use care when enabling it. +# Choices for crypto alg are: (each in lower-case) +# * rsa +# * ec +# * ed + +#set_var EASYRSA_ALGO rsa + +# Define the named curve, used in ec & ed modes: + +#set_var EASYRSA_CURVE secp384r1 + +# In how many days should the root CA key expire? + +#set_var EASYRSA_CA_EXPIRE 3650 + +# In how many days should certificates expire? + +#set_var EASYRSA_CERT_EXPIRE 825 + +# How many days until the next CRL publish date? Note that the CRL can still be +# parsed after this timeframe passes. It is only used for an expected next +# publication date. +#set_var EASYRSA_CRL_DAYS 180 + +# How many days before its expiration date a certificate is allowed to be +# renewed? +#set_var EASYRSA_CERT_RENEW 30 + +# Random serial numbers by default, set to no for the old incremental serial numbers +# +#set_var EASYRSA_RAND_SN "yes" + +# Support deprecated "Netscape" extensions? (choices "yes" or "no".) The default +# is "no" to discourage use of deprecated extensions. If you require this +# feature to use with --ns-cert-type, set this to "yes" here. This support +# should be replaced with the more modern --remote-cert-tls feature. If you do +# not use --ns-cert-type in your configs, it is safe (and recommended) to leave +# this defined to "no". When set to "yes", server-signed certs get the +# nsCertType=server attribute, and also get any NS_COMMENT defined below in the +# nsComment field. + +#set_var EASYRSA_NS_SUPPORT "no" + +# When NS_SUPPORT is set to "yes", this field is added as the nsComment field. +# Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored. + +#set_var EASYRSA_NS_COMMENT "Easy-RSA Generated Certificate" + +# A temp file used to stage cert extensions during signing. The default should +# be fine for most users; however, some users might want an alternative under a +# RAM-based FS, such as /dev/shm or /tmp on some systems. + +#set_var EASYRSA_TEMP_FILE "$EASYRSA_PKI/extensions.temp" + +# !! +# NOTE: ADVANCED OPTIONS BELOW THIS POINT +# PLAY WITH THEM AT YOUR OWN RISK +# !! + +# Broken shell command aliases: If you have a largely broken shell that is +# missing any of these POSIX-required commands used by Easy-RSA, you will need +# to define an alias to the proper path for the command. The symptom will be +# some form of a 'command not found' error from your shell. This means your +# shell is BROKEN, but you can hack around it here if you really need. These +# shown values are not defaults: it is up to you to know what you're doing if +# you touch these. +# +#alias awk="/alt/bin/awk" +#alias cat="/alt/bin/cat" + +# X509 extensions directory: +# If you want to customize the X509 extensions used, set the directory to look +# for extensions here. Each cert type you sign must have a matching filename, +# and an optional file named 'COMMON' is included first when present. Note that +# when undefined here, default behaviour is to look in $EASYRSA_PKI first, then +# fallback to $EASYRSA for the 'x509-types' dir. You may override this +# detection with an explicit dir here. +# +#set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types" + +# If you want to generate KDC certificates, you need to set the realm here. +#set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM" + +# OpenSSL config file: +# If you need to use a specific openssl config file, you can reference it here. +# Normally this file is auto-detected from a file named openssl-easyrsa.cnf from the +# EASYRSA_PKI or EASYRSA dir (in that order.) NOTE that this file is Easy-RSA +# specific and you cannot just use a standard config file, so this is an +# advanced feature. + +#set_var EASYRSA_SSL_CONF "$EASYRSA/openssl-easyrsa.cnf" + +# Default CN: +# This is best left alone. Interactively you will set this manually, and BATCH +# callers are expected to set this themselves. + +#set_var EASYRSA_REQ_CN "ChangeMe" + +# Cryptographic digest to use. +# Do not change this default unless you understand the security implications. +# Valid choices include: md5, sha1, sha256, sha224, sha384, sha512 + +#set_var EASYRSA_DIGEST "sha256" + +# Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly +# in batch mode without any user input, confirmation on dangerous operations, +# or most output. Setting this to any non-blank string enables batch mode. + +#set_var EASYRSA_BATCH "" + diff --git a/deploy/data/windows/easyrsa/x509-types/COMMON b/deploy/data/windows/easyrsa/x509-types/COMMON new file mode 100644 index 00000000..3e9b633f --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/COMMON @@ -0,0 +1,7 @@ +# X509 extensions added to every signed cert + +# This file is included for every cert signed, and by default does nothing. +# It could be used to add values every cert should have, such as a CDP as +# demonstrated in the following example: + +#crlDistributionPoints = URI:http://example.net/pki/my_ca.crl diff --git a/deploy/data/windows/easyrsa/x509-types/ca b/deploy/data/windows/easyrsa/x509-types/ca new file mode 100644 index 00000000..ef525b6f --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/ca @@ -0,0 +1,13 @@ +# X509 extensions for a ca + +# Note that basicConstraints will be overridden by Easy-RSA when defining a +# CA_PATH_LEN for CA path length limits. You could also do this here +# manually as in the following example in place of the existing line: +# +# basicConstraints = CA:TRUE, pathlen:1 + +basicConstraints = CA:TRUE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +keyUsage = cRLSign, keyCertSign + diff --git a/deploy/data/windows/easyrsa/x509-types/client b/deploy/data/windows/easyrsa/x509-types/client new file mode 100644 index 00000000..a7d81af4 --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/client @@ -0,0 +1,8 @@ +# X509 extensions for a client + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = clientAuth +keyUsage = digitalSignature + diff --git a/deploy/data/windows/easyrsa/x509-types/code-signing b/deploy/data/windows/easyrsa/x509-types/code-signing new file mode 100644 index 00000000..05de2a51 --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/code-signing @@ -0,0 +1,8 @@ +# X509 extensions for a client + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = codeSigning +keyUsage = digitalSignature + diff --git a/deploy/data/windows/easyrsa/x509-types/email b/deploy/data/windows/easyrsa/x509-types/email new file mode 100644 index 00000000..7daa88ef --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/email @@ -0,0 +1,8 @@ +# X509 extensions for email + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = emailProtection +keyUsage = digitalSignature,keyEncipherment,nonRepudiation + diff --git a/deploy/data/windows/easyrsa/x509-types/kdc b/deploy/data/windows/easyrsa/x509-types/kdc new file mode 100644 index 00000000..702ec0a2 --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/kdc @@ -0,0 +1,21 @@ +# X509 extensions for a KDC server certificate + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = 1.3.6.1.5.2.3.5 +keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement +issuerAltName = issuer:copy +subjectAltName = otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name + +[kdc_princ_name] +realm = EXP:0,GeneralString:${ENV::EASYRSA_KDC_REALM} +principal_name = EXP:1,SEQUENCE:kdc_principal_seq + +[kdc_principal_seq] +name_type = EXP:0,INTEGER:1 +name_string = EXP:1,SEQUENCE:kdc_principals + +[kdc_principals] +princ1 = GeneralString:krbtgt +princ2 = GeneralString:${ENV::EASYRSA_KDC_REALM} diff --git a/deploy/data/windows/easyrsa/x509-types/server b/deploy/data/windows/easyrsa/x509-types/server new file mode 100644 index 00000000..bc024be5 --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/server @@ -0,0 +1,8 @@ +# X509 extensions for a server + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = serverAuth +keyUsage = digitalSignature,keyEncipherment + diff --git a/deploy/data/windows/easyrsa/x509-types/serverClient b/deploy/data/windows/easyrsa/x509-types/serverClient new file mode 100644 index 00000000..774fe514 --- /dev/null +++ b/deploy/data/windows/easyrsa/x509-types/serverClient @@ -0,0 +1,8 @@ +# X509 extensions for a client/server + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = serverAuth,clientAuth +keyUsage = digitalSignature,keyEncipherment + diff --git a/deploy/data/windows/openvpn/i386/libcrypto-1_1.dll b/deploy/data/windows/openvpn/i386/libcrypto-1_1.dll new file mode 100644 index 00000000..3ce169c2 Binary files /dev/null and b/deploy/data/windows/openvpn/i386/libcrypto-1_1.dll differ diff --git a/deploy/data/windows/openvpn/i386/liblzo2-2.dll b/deploy/data/windows/openvpn/i386/liblzo2-2.dll new file mode 100644 index 00000000..e88d1766 Binary files /dev/null and b/deploy/data/windows/openvpn/i386/liblzo2-2.dll differ diff --git a/deploy/data/windows/openvpn/i386/libpkcs11-helper-1.dll b/deploy/data/windows/openvpn/i386/libpkcs11-helper-1.dll new file mode 100644 index 00000000..5cfddebe Binary files /dev/null and b/deploy/data/windows/openvpn/i386/libpkcs11-helper-1.dll differ diff --git a/deploy/data/windows/openvpn/i386/libssl-1_1.dll b/deploy/data/windows/openvpn/i386/libssl-1_1.dll new file mode 100644 index 00000000..d28402fe Binary files /dev/null and b/deploy/data/windows/openvpn/i386/libssl-1_1.dll differ diff --git a/deploy/data/windows/openvpn/i386/license.txt b/deploy/data/windows/openvpn/i386/license.txt new file mode 100644 index 00000000..68661860 --- /dev/null +++ b/deploy/data/windows/openvpn/i386/license.txt @@ -0,0 +1,555 @@ +OpenVPN (TM) -- An Open Source VPN daemon + +Copyright (C) 2002-2018 OpenVPN Inc + +This distribution contains multiple components, some +of which fall under different licenses. By using OpenVPN +or any of the bundled components enumerated below, you +agree to be bound by the conditions of the license for +each respective component. + +OpenVPN trademark +----------------- + + "OpenVPN" is a trademark of OpenVPN Inc + + +OpenVPN license: +---------------- + + OpenVPN is distributed under the GPL license version 2 (see Below). + + Special exception for linking OpenVPN with OpenSSL: + + In addition, as a special exception, OpenVPN Inc gives + permission to link the code of this program with the OpenSSL + library (or with modified versions of OpenSSL that use the same + license as OpenSSL), and distribute linked combinations including + the two. You must obey the GNU General Public License in all + respects for all of the code used other than OpenSSL. If you modify + this file, you may extend this exception to your version of the + file, but you are not obligated to do so. If you do not wish to + do so, delete this exception statement from your version. + +LZO license: +------------ + + LZO is Copyright (C) Markus F.X.J. Oberhumer, + and is licensed under the GPL. + + Special exception for linking OpenVPN with both OpenSSL and LZO: + + Hereby I grant a special exception to the OpenVPN project + (http://openvpn.net/) to link the LZO library with + the OpenSSL library (http://www.openssl.org). + + Markus F.X.J. Oberhumer + +TAP-Win32/TAP-Win64 Driver license: +----------------------------------- + + This device driver was inspired by the CIPE-Win32 driver by + Damion K. Wilson. + + The source and object code of the TAP-Win32/TAP-Win64 driver + is Copyright (C) 2002-2018 OpenVPN Inc, and is released under + the GPL version 2. + +Windows DDK Samples: +-------------------- + + The Windows binary distribution includes devcon.exe, a + Microsoft DDK sample which is redistributed under the terms + of the DDK EULA. + +NSIS License: +------------- + + Copyright (C) 2002-2003 Joost Verburg + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the + product documentation would be appreciated but is not required. + 2. Altered versions must be plainly marked as such, + and must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any distribution. + +OpenSSL License: +---------------- + + The OpenSSL toolkit stays under a dual license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. 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. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +GNU Public License (GPL) +------------------------ + + OpenVPN, LZO, and the TAP-Win32 distributions are + licensed under the GPL version 2 (see COPYRIGHT.GPL). + + In the Windows binary distribution of OpenVPN, the + GPL is reproduced below. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/deploy/data/windows/openvpn/i386/openvpn.exe b/deploy/data/windows/openvpn/i386/openvpn.exe new file mode 100644 index 00000000..f9f8314c Binary files /dev/null and b/deploy/data/windows/openvpn/i386/openvpn.exe differ diff --git a/deploy/data/windows/openvpn/license.txt b/deploy/data/windows/openvpn/license.txt new file mode 100644 index 00000000..68661860 --- /dev/null +++ b/deploy/data/windows/openvpn/license.txt @@ -0,0 +1,555 @@ +OpenVPN (TM) -- An Open Source VPN daemon + +Copyright (C) 2002-2018 OpenVPN Inc + +This distribution contains multiple components, some +of which fall under different licenses. By using OpenVPN +or any of the bundled components enumerated below, you +agree to be bound by the conditions of the license for +each respective component. + +OpenVPN trademark +----------------- + + "OpenVPN" is a trademark of OpenVPN Inc + + +OpenVPN license: +---------------- + + OpenVPN is distributed under the GPL license version 2 (see Below). + + Special exception for linking OpenVPN with OpenSSL: + + In addition, as a special exception, OpenVPN Inc gives + permission to link the code of this program with the OpenSSL + library (or with modified versions of OpenSSL that use the same + license as OpenSSL), and distribute linked combinations including + the two. You must obey the GNU General Public License in all + respects for all of the code used other than OpenSSL. If you modify + this file, you may extend this exception to your version of the + file, but you are not obligated to do so. If you do not wish to + do so, delete this exception statement from your version. + +LZO license: +------------ + + LZO is Copyright (C) Markus F.X.J. Oberhumer, + and is licensed under the GPL. + + Special exception for linking OpenVPN with both OpenSSL and LZO: + + Hereby I grant a special exception to the OpenVPN project + (http://openvpn.net/) to link the LZO library with + the OpenSSL library (http://www.openssl.org). + + Markus F.X.J. Oberhumer + +TAP-Win32/TAP-Win64 Driver license: +----------------------------------- + + This device driver was inspired by the CIPE-Win32 driver by + Damion K. Wilson. + + The source and object code of the TAP-Win32/TAP-Win64 driver + is Copyright (C) 2002-2018 OpenVPN Inc, and is released under + the GPL version 2. + +Windows DDK Samples: +-------------------- + + The Windows binary distribution includes devcon.exe, a + Microsoft DDK sample which is redistributed under the terms + of the DDK EULA. + +NSIS License: +------------- + + Copyright (C) 2002-2003 Joost Verburg + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the + product documentation would be appreciated but is not required. + 2. Altered versions must be plainly marked as such, + and must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any distribution. + +OpenSSL License: +---------------- + + The OpenSSL toolkit stays under a dual license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. 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. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +GNU Public License (GPL) +------------------------ + + OpenVPN, LZO, and the TAP-Win32 distributions are + licensed under the GPL version 2 (see COPYRIGHT.GPL). + + In the Windows binary distribution of OpenVPN, the + GPL is reproduced below. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/deploy/data/windows/tap/i386/OemVista.inf b/deploy/data/windows/tap/i386/OemVista.inf new file mode 100644 index 00000000..85f626b7 --- /dev/null +++ b/deploy/data/windows/tap/i386/OemVista.inf @@ -0,0 +1,191 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** + +; SYNTAX CHECKER +; cd \WINDDK\3790\tools\chkinf +; chkinf c:\src\openvpn\tap-win32\i386\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; Note to Developers: +; +; If you are bundling the TAP-Windows driver with your app, +; you should try to rename it in such a way that it will +; not collide with other instances of TAP-Windows defined +; by other apps. Multiple versions of the TAP-Windows +; driver, each installed by different apps, can coexist +; on the same machine if you follow these guidelines. +; NOTE: these instructions assume you are editing the +; generated OemWin2k.inf file, not the source +; OemWin2k.inf.in file which is preprocessed by winconfig +; and uses macro definitions from settings.in. +; +; (1) Rename all tapXXXX instances in this file to +; something different (use at least 5 characters +; for this name!) +; (2) Change the "!define TAP" definition in openvpn.nsi +; to match what you changed tapXXXX to. +; (3) Change TARGETNAME in SOURCES to match what you +; changed tapXXXX to. +; (4) Change TAP_COMPONENT_ID in common.h to match what +; you changed tapXXXX to. +; (5) Change SZDEPENDENCIES in service.h to match what +; you changed tapXXXX to. +; (6) Change DeviceDescription and Provider strings. +; (7) Change PRODUCT_TAP_WIN_DEVICE_DESCRIPTION in constants.h to what you +; set DeviceDescription to. +; +;********************************************************* + +[Version] + Signature = "$Windows NT$" + CatalogFile = tap0901.cat + ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + Provider = %Provider% + Class = Net + +; This version number should match the version +; number given in ..\version.m4. + DriverVer = 09/27/2019,9.24.2.601 + +[Strings] + DeviceDescription = "TAP-Windows Adapter V9" + Provider = "TAP-Windows Provider V9" + +;---------------------------------------------------------------- +; Manufacturer + Product Section (Done) +;---------------------------------------------------------------- +[Manufacturer] + %Provider% = tap0901, NTx86 + +[tap0901.NTx86] + %DeviceDescription% = tap0901.ndi, root\tap0901 ; Root enumerated + %DeviceDescription% = tap0901.ndi, tap0901 ; Legacy + +;--------------------------------------------------------------- +; Driver Section (Done) +;--------------------------------------------------------------- + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ + +[tap0901.ndi] + CopyFiles = tap0901.driver, tap0901.files + AddReg = tap0901.reg + AddReg = tap0901.params.reg + Characteristics = 0x1 + *IfType = 53 ; IF_TYPE_PROP_VIRTUAL + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified + +[tap0901.ndi.Services] + AddService = tap0901, 2, tap0901.service + +[tap0901.reg] + HKR, Ndi, Service, 0, "tap0901" + HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" + HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + HKR, , Manufacturer, 0, "%Provider%" + HKR, , ProductName, 0, "%DeviceDescription%" + +[tap0901.params.reg] + HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" + HKR, Ndi\params\MTU, Type, 0, "int" + HKR, Ndi\params\MTU, Default, 0, "1500" + HKR, Ndi\params\MTU, Optional, 0, "0" + HKR, Ndi\params\MTU, Min, 0, "100" + HKR, Ndi\params\MTU, Max, 0, "1500" + HKR, Ndi\params\MTU, Step, 0, "1" + HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" + HKR, Ndi\params\MediaStatus, Type, 0, "enum" + HKR, Ndi\params\MediaStatus, Default, 0, "0" + HKR, Ndi\params\MediaStatus, Optional, 0, "0" + HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" + HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" + HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" + HKR, Ndi\params\MAC, Type, 0, "edit" + HKR, Ndi\params\MAC, Optional, 0, "1" + HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" + HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" + HKR, Ndi\params\AllowNonAdmin, Default, 0, "1" + HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" + HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" + HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +;---------------------------------------------------------------- +; Service Section +;---------------------------------------------------------------- + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[tap0901.service] + DisplayName = %DeviceDescription% + ServiceType = 1 + StartType = 3 + ErrorControl = 1 + LoadOrderGroup = NDIS + ServiceBinary = %12%\tap0901.sys + +;----------------------------------------------------------------- +; File Installation +;----------------------------------------------------------------- + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +; SourceDisksNames +; diskid = description[, [tagfile] [, , subdir]] +; 1 = "Intel Driver Disk 1",e100bex.sys,, + +[SourceDisksNames] + 1 = %DeviceDescription%, tap0901.sys + +; SourceDisksFiles +; filename_on_source = diskID[, [subdir][, size]] +; e100bex.sys = 1,, ; on distribution disk 1 + +[SourceDisksFiles] +tap0901.sys = 1 + +[DestinationDirs] + tap0901.files = 11 + tap0901.driver = 12 + +[tap0901.files] +; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK +; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +[tap0901.driver] + tap0901.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +;--------------------------------------------------------------- +; End +;--------------------------------------------------------------- diff --git a/deploy/data/windows/tap/i386/tap0901.cat b/deploy/data/windows/tap/i386/tap0901.cat new file mode 100644 index 00000000..852bd5aa Binary files /dev/null and b/deploy/data/windows/tap/i386/tap0901.cat differ diff --git a/deploy/data/windows/tap/i386/tap0901.sys b/deploy/data/windows/tap/i386/tap0901.sys new file mode 100644 index 00000000..70289962 Binary files /dev/null and b/deploy/data/windows/tap/i386/tap0901.sys differ diff --git a/deploy/data/windows/tap/i386/tapinstall.exe b/deploy/data/windows/tap/i386/tapinstall.exe new file mode 100644 index 00000000..6ffd2eb4 Binary files /dev/null and b/deploy/data/windows/tap/i386/tapinstall.exe differ diff --git a/deploy/data/windows/tap/license.txt b/deploy/data/windows/tap/license.txt new file mode 100644 index 00000000..3fbcff55 --- /dev/null +++ b/deploy/data/windows/tap/license.txt @@ -0,0 +1,365 @@ +tap-windows6 license +-------------------- + +The source and object code of the tap-windows6 project +is Copyright (C) 2002-2014 OpenVPN Technologies, Inc. The +NSIS installer is Copyright (C) 2014 OpenVPN Technologies, +Inc. and (C) 2012 Alon Bar-Lev. Both are released under the +GPL version 2. See COPYRIGHT.GPL for the full GPL license. +The licensors also make the following statement borrowed +from the SPICE project: + +With respect to binaries built using the Microsoft(R) +Windows Driver Kit (WDK), GPLv2 does not extend to any code +contained in or derived from the WDK ("WDK Code"). As to +WDK Code, by using or distributing such binaries you agree +to be bound by the Microsoft Software License Terms for the +WDK. All WDK Code is considered by the GPLv2 licensors to +qualify for the special exception stated in section 3 of +GPLv2 (commonly known as the system library exception). + +The tap-windows.h file has been released under the MIT +license (see COPYRIGHT.MIT) as well as under GPLv2 (see +COPYRIGHT.GPL). This has been done to allow the use of the +header file in non-GPLv2 compatible projects. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/deploy/data/windows/tap/x86_64/OemVista.inf b/deploy/data/windows/tap/x86_64/OemVista.inf new file mode 100644 index 00000000..a765fc14 --- /dev/null +++ b/deploy/data/windows/tap/x86_64/OemVista.inf @@ -0,0 +1,191 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** + +; SYNTAX CHECKER +; cd \WINDDK\3790\tools\chkinf +; chkinf c:\src\openvpn\tap-win32\i386\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; Note to Developers: +; +; If you are bundling the TAP-Windows driver with your app, +; you should try to rename it in such a way that it will +; not collide with other instances of TAP-Windows defined +; by other apps. Multiple versions of the TAP-Windows +; driver, each installed by different apps, can coexist +; on the same machine if you follow these guidelines. +; NOTE: these instructions assume you are editing the +; generated OemWin2k.inf file, not the source +; OemWin2k.inf.in file which is preprocessed by winconfig +; and uses macro definitions from settings.in. +; +; (1) Rename all tapXXXX instances in this file to +; something different (use at least 5 characters +; for this name!) +; (2) Change the "!define TAP" definition in openvpn.nsi +; to match what you changed tapXXXX to. +; (3) Change TARGETNAME in SOURCES to match what you +; changed tapXXXX to. +; (4) Change TAP_COMPONENT_ID in common.h to match what +; you changed tapXXXX to. +; (5) Change SZDEPENDENCIES in service.h to match what +; you changed tapXXXX to. +; (6) Change DeviceDescription and Provider strings. +; (7) Change PRODUCT_TAP_WIN_DEVICE_DESCRIPTION in constants.h to what you +; set DeviceDescription to. +; +;********************************************************* + +[Version] + Signature = "$Windows NT$" + CatalogFile = tap0901.cat + ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + Provider = %Provider% + Class = Net + +; This version number should match the version +; number given in ..\version.m4. + DriverVer = 09/27/2019,9.24.2.601 + +[Strings] + DeviceDescription = "TAP-Windows Adapter V9" + Provider = "TAP-Windows Provider V9" + +;---------------------------------------------------------------- +; Manufacturer + Product Section (Done) +;---------------------------------------------------------------- +[Manufacturer] + %Provider% = tap0901, NTamd64 + +[tap0901.NTamd64] + %DeviceDescription% = tap0901.ndi, root\tap0901 ; Root enumerated + %DeviceDescription% = tap0901.ndi, tap0901 ; Legacy + +;--------------------------------------------------------------- +; Driver Section (Done) +;--------------------------------------------------------------- + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ + +[tap0901.ndi] + CopyFiles = tap0901.driver, tap0901.files + AddReg = tap0901.reg + AddReg = tap0901.params.reg + Characteristics = 0x1 + *IfType = 53 ; IF_TYPE_PROP_VIRTUAL + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified + +[tap0901.ndi.Services] + AddService = tap0901, 2, tap0901.service + +[tap0901.reg] + HKR, Ndi, Service, 0, "tap0901" + HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" + HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + HKR, , Manufacturer, 0, "%Provider%" + HKR, , ProductName, 0, "%DeviceDescription%" + +[tap0901.params.reg] + HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" + HKR, Ndi\params\MTU, Type, 0, "int" + HKR, Ndi\params\MTU, Default, 0, "1500" + HKR, Ndi\params\MTU, Optional, 0, "0" + HKR, Ndi\params\MTU, Min, 0, "100" + HKR, Ndi\params\MTU, Max, 0, "1500" + HKR, Ndi\params\MTU, Step, 0, "1" + HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" + HKR, Ndi\params\MediaStatus, Type, 0, "enum" + HKR, Ndi\params\MediaStatus, Default, 0, "0" + HKR, Ndi\params\MediaStatus, Optional, 0, "0" + HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" + HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" + HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" + HKR, Ndi\params\MAC, Type, 0, "edit" + HKR, Ndi\params\MAC, Optional, 0, "1" + HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" + HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" + HKR, Ndi\params\AllowNonAdmin, Default, 0, "1" + HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" + HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" + HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +;---------------------------------------------------------------- +; Service Section +;---------------------------------------------------------------- + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[tap0901.service] + DisplayName = %DeviceDescription% + ServiceType = 1 + StartType = 3 + ErrorControl = 1 + LoadOrderGroup = NDIS + ServiceBinary = %12%\tap0901.sys + +;----------------------------------------------------------------- +; File Installation +;----------------------------------------------------------------- + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +; SourceDisksNames +; diskid = description[, [tagfile] [, , subdir]] +; 1 = "Intel Driver Disk 1",e100bex.sys,, + +[SourceDisksNames] + 1 = %DeviceDescription%, tap0901.sys + +; SourceDisksFiles +; filename_on_source = diskID[, [subdir][, size]] +; e100bex.sys = 1,, ; on distribution disk 1 + +[SourceDisksFiles] +tap0901.sys = 1 + +[DestinationDirs] + tap0901.files = 11 + tap0901.driver = 12 + +[tap0901.files] +; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK +; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +[tap0901.driver] + tap0901.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +;--------------------------------------------------------------- +; End +;--------------------------------------------------------------- diff --git a/deploy/data/windows/tap/x86_64/tap0901.cat b/deploy/data/windows/tap/x86_64/tap0901.cat new file mode 100644 index 00000000..22b0096c Binary files /dev/null and b/deploy/data/windows/tap/x86_64/tap0901.cat differ diff --git a/deploy/data/windows/tap/x86_64/tap0901.sys b/deploy/data/windows/tap/x86_64/tap0901.sys new file mode 100644 index 00000000..55fcac21 Binary files /dev/null and b/deploy/data/windows/tap/x86_64/tap0901.sys differ diff --git a/deploy/data/windows/tap/x86_64/tapinstall.exe b/deploy/data/windows/tap/x86_64/tapinstall.exe new file mode 100644 index 00000000..6e26987f Binary files /dev/null and b/deploy/data/windows/tap/x86_64/tapinstall.exe differ diff --git a/deploy/installer/config/controlscript.js b/deploy/installer/config/controlscript.js new file mode 100644 index 00000000..d5ea5c54 --- /dev/null +++ b/deploy/installer/config/controlscript.js @@ -0,0 +1,329 @@ +var requestToQuitFromApp = false; +var updaterCompleted = 0; +var desktopAppProcessRunning = false; +var appInstalledUninstallerPath; + +function appName() +{ + return installer.value("Name"); +} + +function appAlreadyInstalled() +{ + return installer.fileExists(appInstalledUninstallerPath); +} + +function appExecutableFileName() +{ + if (runningOnWindows()) { + return appName() + ".exe"; + } else { + return appName(); + } +} + +function appInstalled() +{ + if (runningOnWindows()) { + appInstalledUninstallerPath = installer.value("TargetDir") + "\\maintenancetool.exe"; + } else if (runningOnMacOS()){ + appInstalledUninstallerPath = "/Applications/" + appName() + ".app/maintenancetool.app/Contents/MacOS/maintenancetool"; + } + + return appAlreadyInstalled(); +} + +function endsWith(str, suffix) +{ + return str.indexOf(suffix, str.length - suffix.length) !== -1; +} + +function runningOnWindows() +{ + return (installer.value("os") === "win"); +} + +function runningOnMacOS() +{ + return (installer.value("os") === "mac"); +} + +function sleep(miliseconds) { + var currentTime = new Date().getTime(); + while (currentTime + miliseconds >= new Date().getTime()) {} +} + +function raiseInstallerWindow() +{ + if (!runningOnMacOS()) { + return; + } + + var result = installer.execute("/bin/bash", ["-c", "ps -A | grep -m1 '" + appName() + "' | awk '{print $1}'"]); + if (Number(result[0]) > 0) { + var arg = 'tell application \"System Events\" ' + + '\n set frontmost of the first process whose unix id is ' + Number(result[0]) + ' to true ' + + '\n end tell' + + '\n '; + installer.execute("osascript", ["-e", arg]); + } +} + +function appProcessIsRunning() +{ + if (runningOnWindows()) { + var cmdArgs = ["/FI", "WINDOWTITLE eq " + appName()]; + var result = installer.execute("tasklist", cmdArgs); + + if ( Number(result[1]) === 0 ) { + if (result[0].indexOf(appExecutableFileName()) !== -1) { + return true; + } + } + } else { + return checkProccesIsRunning("pgrep -x '" + appName() + "'") + } + + return false; +} + +function checkProccesIsRunning(arg) +{ + var cmdArgs = ["-c", arg]; + var result = installer.execute("/bin/bash", cmdArgs); + var resultArg1 = Number(result[0]) + if (resultArg1 >= 3) { + return true; + } + return false; +} + +function requestToQuit(installer,gui) +{ + requestToQuitFromApp = true; + + installer.setDefaultPageVisible(QInstaller.IntroductionPage, false); + installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); + installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); + installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); + installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); + installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); + installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); + installer.setDefaultPageVisible(QInstaller.FinishedPage, false); + + gui.clickButton(buttons.NextButton); + gui.clickButton(buttons.FinishButton); + gui.clickButton(buttons.CancelButton); + + if (runningOnWindows()) { + installer.setCancelled(); + } +} + + +Controller.prototype.PerformInstallationPageCallback = function() +{ + gui.clickButton(buttons.NextButton); +} + +Controller.prototype.LicenseAgreementPageCallback = function() +{ + gui.clickButton(buttons.NextButton); +} + +Controller.prototype.FinishedPageCallback = function () +{ + if (desktopAppProcessRunning) { + gui.clickButton(buttons.FinishButton); + } else if (installer.isUpdater()) { + installer.autoAcceptMessageBoxes(); + gui.clickButton(buttons.FinishButton); + } +} + +Controller.prototype.RestartPageCallback = function () +{ + updaterCompleted = 1; + gui.clickButton(buttons.FinishButton); +} + +Controller.prototype.StartMenuDirectoryPageCallback = function() +{ + gui.clickButton(buttons.NextButton); +} + +Controller.prototype.ComponentSelectionPageCallback = function() +{ + gui.clickButton(buttons.NextButton); +} + +Controller.prototype.ReadyForInstallationPageCallback = function() +{ + if (installer.isUpdater()) { + gui.clickButton(buttons.CommitButton); + } +} + +Controller.prototype.TargetDirectoryPageCallback = function () +{ + var widget = gui.pageById(QInstaller.TargetDirectory); + + if (widget !== null) { + widget.BrowseDirectoryButton.clicked.disconnect(onBrowseButtonClicked); + widget.BrowseDirectoryButton.clicked.connect(onBrowseButtonClicked); + + gui.clickButton(buttons.NextButton); + } +} + +Controller.prototype.IntroductionPageCallback = function () +{ + var widget = gui.currentPageWidget(); + if (installer.isUpdater() && updaterCompleted === 1) { + gui.clickButton(buttons.FinishButton); + gui.clickButton(buttons.CancelButton); + return; + } + + if (installer.isUninstaller()) { + if (widget !== null) { + widget.findChild("PackageManagerRadioButton").visible = false; + widget.findChild("UpdaterRadioButton").visible = false; + } + } + + if (installer.isUpdater()) { + gui.clickButton(buttons.NextButton); + } +} + +onBrowseButtonClicked = function() +{ + var widget = gui.pageById(QInstaller.TargetDirectory); + if (widget !== null) { + if (runningOnWindows()) { + // On Windows we are appending \ if selected path don't ends with + var targetDir = widget.TargetDirectoryLineEdit.text; + if (! endsWith(targetDir, appName())) { + targetDir = targetDir + "\\" + appName(); + } + installer.setValue("TargetDir", targetDir); + widget.TargetDirectoryLineEdit.setText(installer.value("TargetDir")); + } + } +} + +onNextButtonClicked = function() +{ + var widget = gui.pageById(QInstaller.TargetDirectory); + if (widget !== null) { + installer.setValue("APP_BUNDLE_TARGET_DIR", widget.TargetDirectoryLineEdit.text); + } +} + +function Controller () { + console.log("OS: %1, architecture: %2".arg(systemInfo.prettyProductName).arg(systemInfo.currentCpuArchitecture)); + + if (installer.isInstaller() || installer.isUpdater()) { + console.log("Check if app already installed: " + appInstalled()); + } + + if (runningOnWindows()) { + installer.setValue("AllUsers", "true"); + } + + if (installer.isInstaller()) { + installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); + installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); + installer.setDefaultPageVisible(QInstaller.StartMenuDirectoryPage, false); + installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); + + isDesktopAppProcessRunningMessageLoop(); + + if (requestToQuitFromApp === true) { + requestToQuit(installer, gui); + return; + } + + if (runningOnMacOS()) { + installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes); + } + + if (appAlreadyInstalled()) { + if (QMessageBox.Ok === QMessageBox.information("os.information", appName(), + qsTr("The application is already installed.") + " " + + qsTr("We need to remove the old installation first. Do you wish to proceed?"), + QMessageBox.Ok | QMessageBox.Cancel)) { + + if (appAlreadyInstalled()) { + var resultArray = installer.execute(appInstalledUninstallerPath); + + console.log("Uninstaller finished with code: " + resultArray[1]) + + if (Number(resultArray[1]) !== 0) { + console.log("Uninstallation aborted by user"); + installer.setCancelled(); + return; + } else { + for (var i = 0; i < 100; i++) { + sleep(100); + if (!installer.fileExists(appInstalledUninstallerPath)) { + break; + } + } + } + } + + raiseInstallerWindow(); + + } else { + console.log("Request to quit from user"); + installer.setCancelled(); + return; + } + } + + } else if (installer.isUninstaller()) { + isDesktopAppProcessRunningMessageLoop(); + + if (requestToQuitFromApp === true) { + requestToQuit(installer, gui); + return; + } + + } else if (installer.isUpdater()) { + installer.setMessageBoxAutomaticAnswer("cancelInstallation", QMessageBox.No); + installer.installationFinished.connect(function() { + gui.clickButton(buttons.NextButton); + }); + } +} + +isDesktopAppProcessRunningMessageLoop = function () +{ + if (requestToQuitFromApp === true) { + return; + } + + if (installer.isUpdater()) { + for (var i = 0; i < 400; i++) { + desktopAppProcessRunning = appProcessIsRunning(); + if (!desktopAppProcessRunning) { + break; + } + } + } + desktopAppProcessRunning = appProcessIsRunning(); + + if (desktopAppProcessRunning) { + var result = QMessageBox.warning("QMessageBox", appName() + " installer", + appName() + " is active. Close the app and press \"Retry\" button to continue installation. Press \"Abort\" button to abort the installer and exit.", + QMessageBox.Retry | QMessageBox.Abort); + if (result === QMessageBox.Retry) { + isDesktopAppProcessRunningMessageLoop(); + } else { + requestToQuitFromApp = true; + return; + } + } +} diff --git a/deploy/installer/config/macos.xml b/deploy/installer/config/macos.xml new file mode 100644 index 00000000..82edef16 --- /dev/null +++ b/deploy/installer/config/macos.xml @@ -0,0 +1,27 @@ + + + AmneziaVPN + 1.0.0 + AmneziaVPN + AmneziaVPN + AmneziaVPN + /Applications/AmneziaVPN.app + 600 + 380 + Modern + true + true + false + controlscript.js + false + true + false + true + + + https://amneziavpn.org/updates/macos + true + AmneziaVPN - repository for macOS + + + diff --git a/deploy/installer/config/windows.xml b/deploy/installer/config/windows.xml new file mode 100644 index 00000000..18728f64 --- /dev/null +++ b/deploy/installer/config/windows.xml @@ -0,0 +1,27 @@ + + + AmneziaVPN + 1.0.0 + AmneziaVPN + AmneziaVPN + AmneziaVPN + @ApplicationsDir@/AmneziaVPN + 600 + 380 + Modern + true + true + false + controlscript.js + false + true + false + true + + + https://amneziavpn.org/updates/windows + true + AmneziaVPN - repository for Windows + + + diff --git a/deploy/installer/packages/org.amneziavpn.package/meta/componentscript.js b/deploy/installer/packages/org.amneziavpn.package/meta/componentscript.js new file mode 100644 index 00000000..94128aef --- /dev/null +++ b/deploy/installer/packages/org.amneziavpn.package/meta/componentscript.js @@ -0,0 +1,115 @@ + +function appName() +{ + return installer.value("Name") +} + +function serviceName() +{ + return (appName() + "-service") +} + +function appExecutableFileName() +{ + if (runningOnWindows()) { + return appName() + ".exe"; + } else { + return appName(); + } +} + +function runningOnWindows() +{ + return (systemInfo.kernelType === "winnt"); +} + +function runningOnMacOS() +{ + return (systemInfo.kernelType === "darwin"); +} + +function vcRuntimeIsInstalled() +{ + return (installer.findPath("msvcp140.dll", [installer.value("RootDir")+ "\\Windows\\System32\\"]).length !== 0) +} + +function Component() +{ + component.loaded.connect(this, Component.prototype.componentLoaded); + installer.installationFinished.connect(this, Component.prototype.installationFinishedPageIsShown); + installer.finishButtonClicked.connect(this, Component.prototype.installationFinished); +} + +Component.prototype.componentLoaded = function () +{ + +} + +Component.prototype.installationFinishedPageIsShown = function() +{ + if (installer.isInstaller() && installer.status === QInstaller.Success) { + gui.clickButton(buttons.FinishButton); + } +} + +Component.prototype.createOperations = function() +{ + component.createOperations(); + + if (runningOnWindows()) { + + component.addOperation("CreateShortcut", "@TargetDir@/" + appExecutableFileName(), + QDesktopServices.storageLocation(QDesktopServices.DesktopLocation) + "/" + appName() + ".lnk", + "workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\" + appExecutableFileName(), "iconId=0"); + + + component.addElevatedOperation("CreateShortcut", "@TargetDir@/" + appExecutableFileName(), + installer.value("AllUsersStartMenuProgramsPath") + "/" + appName() + ".lnk", + "workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\" + appExecutableFileName(), "iconId=0"); + + if (!vcRuntimeIsInstalled()) { + component.addElevatedOperation("Execute", "@TargetDir@\\" + "vc_redist.x86.exe", "/install", "/quiet", "/norestart", "/log", "vc_redist_2017_x86.log"); + } else { + console.log("Microsoft Visual C++ 2017 Redistributable already installed"); + } + + component.addElevatedOperation("Execute", + ["sc", "create", serviceName(), "binpath=", installer.value("TargetDir").replace(/\//g, '\\') + "\\" + serviceName() + ".exe", + "start=", "auto", "depend=", "BFE/nsi"], + "UNDOEXECUTE", ["post-uninstall.exe"]); + + } else if (runningOnMacOS()) { + component.addElevatedOperation("Execute", "@TargetDir@/post_install.sh", "UNDOEXECUTE", "@TargetDir@/post_uninstall.sh"); + } +} + +Component.prototype.installationFinished = function() +{ + var command = ""; + var args = []; + + if ((installer.status === QInstaller.Success) && (installer.isInstaller() || installer.isUpdater())) { + + if (!installer.gainAdminRights()) { + console.log("Fatal error! Cannot get admin rights!") + return + } + + if (runningOnWindows()) { + command = "@TargetDir@/" + appExecutableFileName() + + var status1 = installer.execute("net", ["start", serviceName()]) + console.log(("%1 started with status: %2 ").arg(serviceName()).arg(status1)) + + var status2 = installer.execute("sc", ["failure", serviceName(), "reset=", "100", "actions=", "restart/2000/restart/2000/restart/2000"]) + console.log(("Changed settings for %1 with status: %2 ").arg(serviceName()).arg(status2)) + + } else if (runningOnMacOS()) { + command = "/Applications/" + appName() + ".app/Contents/MacOS/" + appName(); + } + + installer.dropAdminRights() + + processStatus = installer.executeDetached(command, args, installer.value("TargetDir")); + } +} diff --git a/deploy/installer/packages/org.amneziavpn.package/meta/package.xml b/deploy/installer/packages/org.amneziavpn.package/meta/package.xml new file mode 100644 index 00000000..a5db6b61 --- /dev/null +++ b/deploy/installer/packages/org.amneziavpn.package/meta/package.xml @@ -0,0 +1,12 @@ + + + AmneziaVPN + Installation package for AmneziaVPN + 1.0.0 + 1970-01-01 + true + true + true + + + diff --git a/deploy/macos.sh b/deploy/macos.sh new file mode 100644 index 00000000..32659b7e --- /dev/null +++ b/deploy/macos.sh @@ -0,0 +1,58 @@ +#!/bin/bash -ex + + +QT_BIN_DIR='/Users/admin/Qt/5.14.2/clang_64/bin' +QIF_BIN_DIR='/Users/admin/Qt/Tools/QtInstallerFramework/4.0/bin' + +APP_NAME=AmneziaVPN +APP_FILENAME=$APP_NAME.app +APP_DOMAIN=org.amneziavpn.package +PLIST_NAME=$APP_NAME.plist + +LAUNCH_DIR=$(pwd) +TOP_DIR=$LAUNCH_DIR/.. +RELEASE_DIR=$TOP_DIR/../$APP_NAME-build +OUT_APP_DIR=$RELEASE_DIR/client/release +BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME +DEPLOY_DATA_DIR=$LAUNCH_DIR/data/macos +INSTALLER_DATA_DIR=$RELEASE_DIR/installer/packages/$APP_DOMAIN/data + +PRO_FILE_PATH=$TOP_DIR/$APP_NAME.pro +QMAKE_STASH_FILE=$TOP_DIR/.qmake_stash +TARGET_FILENAME=$TOP_DIR/$APP_NAME.dmg + +cleanBuild() +{ + rm -rf $RELEASE_DIR + rm -rf $QMAKE_STASH_FILE +} + + +cleanBuild + +cd $TOP_DIR +$QT_BIN_DIR/qmake $PRO_FILE_PATH 'CONFIG+=release CONFIG+=x86_64' +make -j `sysctl -n hw.ncpu` + +$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite +cp -av $RELEASE_DIR/server/release/$APP_NAME-service.app/Contents/macOS/$APP_NAME-service $BUNDLE_DIR/Contents/macOS +cp -av $LAUNCH_DIR/data/macos/openvpn $BUNDLE_DIR/Contents/macOS + +mkdir -p $INSTALLER_DATA_DIR +cp -av $LAUNCH_DIR/installer $RELEASE_DIR +cp -av $DEPLOY_DATA_DIR/post_install.sh $INSTALLER_DATA_DIR/post_install.sh +cp -av $DEPLOY_DATA_DIR/post_uninstall.sh $INSTALLER_DATA_DIR/post_uninstall.sh +cp -av $DEPLOY_DATA_DIR/$PLIST_NAME $INSTALLER_DATA_DIR/$PLIST_NAME + +cd $BUNDLE_DIR +tar czf $INSTALLER_DATA_DIR/$APP_NAME.tar.gz ./ + +cd $RELEASE_DIR/installer +$QIF_BIN_DIR/binarycreator --offline-only -v -c config/macos.xml -p packages -f $APP_NAME +hdiutil create -volname $APP_NAME -srcfolder $APP_NAME.app -ov -format UDZO $TARGET_FILENAME + +cleanBuild + +cd $LAUNCH_DIR + +echo "Finished, see $APP_NAME.dmg in '$TOP_DIR'" diff --git a/deploy/windows-env.bat b/deploy/windows-env.bat new file mode 100644 index 00000000..349bd868 --- /dev/null +++ b/deploy/windows-env.bat @@ -0,0 +1 @@ +"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\VsDevCmd.bat" diff --git a/deploy/windows.bat b/deploy/windows.bat new file mode 100644 index 00000000..1a1bd1d9 --- /dev/null +++ b/deploy/windows.bat @@ -0,0 +1,71 @@ + @ECHO OFF + +CHCP 1252 + +SET QT_BIN_DIR="c:\Devel\Qt\5.14.2\msvc2017\bin" +SET QIF_BIN_DIR="c:\Devel\Qt\Tools\QtInstallerFramework\4.0\bin" + +set APP_NAME=AmneziaVPN +set APP_FILENAME=%APP_NAME:"=%.exe +set APP_DOMAIN=org.amneziavpn.package +set LAUNCH_DIR=%cd% +set TOP_DIR=%LAUNCH_DIR:"=%\.. +set RELEASE_DIR=%TOP_DIR:"=%\..\%APP_NAME:"=%-build +set OUT_APP_DIR=%RELEASE_DIR:"=%\client\release +set DEPLOY_DATA_DIR=%LAUNCH_DIR:"=%\data\windows +set INSTALLER_DATA_DIR=%RELEASE_DIR:"=%\installer\packages\%APP_DOMAIN:"=%\data +set PRO_FILE_PATH=%TOP_DIR:"=%\%APP_NAME:"=%.pro +set QMAKE_STASH_FILE=%TOP_DIR:"=%\.qmake_stash +set TARGET_FILENAME=%TOP_DIR:"=%\%APP_NAME:"=%.exe + +echo "Environment:" +echo "APP_FILENAME: %APP_FILENAME%" +echo "LAUNCH_DIR: %LAUNCH_DIR%" +echo "TOP_DIR: %TOP_DIR%" +echo "RELEASE_DIR: %RELEASE_DIR%" +echo "OUT_APP_DIR: %OUT_APP_DIR%" +echo "DEPLOY_DATA_DIR: %DEPLOY_DATA_DIR%" +echo "INSTALLER_DATA_DIR: %INSTALLER_DATA_DIR%" +echo "PRO_FILE_PATH: %PRO_FILE_PATH%" +echo "QMAKE_STASH_FILE: %QMAKE_STASH_FILE%" +echo "TARGET_FILENAME: %TARGET_FILENAME%" + +echo "Cleanup..." +Rmdir /Q /S %RELEASE_DIR% +Del %QMAKE_STASH_FILE% +Del %TARGET_FILENAME% + + +cd %TOP_DIR% +"%QT_BIN_DIR:"=%\qmake" %PRO_FILE_PATH% -spec win32-msvc +set CL=/MP +nmake /A /NOLOGO +del "%OUT_APP_DIR:"=%\*.obj" +del "%OUT_APP_DIR:"=%\*.cpp" +del "%OUT_APP_DIR:"=%\*.h" +del "%OUT_APP_DIR:"=%\*.res" +del "%OUT_APP_DIR:"=%\*.o" +del "%OUT_APP_DIR:"=%\*.lib" +del "%OUT_APP_DIR:"=%\*.exp" +echo "Deploying..." +"%QT_BIN_DIR:"=%\windeployqt" --release --force --no-translations "%OUT_APP_DIR:"=%\%APP_FILENAME:"=%" +echo "Copying deploy data..." +xcopy %DEPLOY_DATA_DIR% %OUT_APP_DIR% /s /e /y /i /f +copy "%RELEASE_DIR:"=%\server\release\%APP_NAME:"=%-service.exe" %OUT_APP_DIR% +copy "%RELEASE_DIR:"=%\post-uninstall\release\post-uninstall.exe" %OUT_APP_DIR% + +cd %LAUNCH_DIR% +xcopy %LAUNCH_DIR:"=%\installer %RELEASE_DIR:"=%\installer /s /e /y /i /f +mkdir %INSTALLER_DATA_DIR% + +cd %OUT_APP_DIR% +echo "Compressing data..." +"%QIF_BIN_DIR:"=%\archivegen" -c 9 %INSTALLER_DATA_DIR:"=%\%APP_NAME:"=%.7z ./ + +cd "%RELEASE_DIR:"=%\installer" +echo "Creating installer..." +"%QIF_BIN_DIR:"=%\binarycreator" --offline-only -v -c config\windows.xml -p packages -f %TARGET_FILENAME% + + +cd %LAUNCH_DIR% +echo "Finished, see %TARGET_FILENAME%" diff --git a/platform/platform.pro b/platform/platform.pro new file mode 100644 index 00000000..4ed46764 --- /dev/null +++ b/platform/platform.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +win32 { + SUBDIRS += post-uninstall +} diff --git a/platform/post-uninstall/main.cpp b/platform/post-uninstall/main.cpp new file mode 100644 index 00000000..3be66a13 --- /dev/null +++ b/platform/post-uninstall/main.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include "defines.h" + +bool executeProcess(const QString& cmd, const QStringList& args) +{ + QProcess process; + process.start(cmd, args); + return process.waitForFinished(); +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + executeProcess("sc", QStringList() << "stop" << SERVICE_NAME); + executeProcess("sc", QStringList() << "delete" << SERVICE_NAME); + + return 0; +} diff --git a/platform/post-uninstall/post-uninstall.pro b/platform/post-uninstall/post-uninstall.pro new file mode 100644 index 00000000..a59aa9f8 --- /dev/null +++ b/platform/post-uninstall/post-uninstall.pro @@ -0,0 +1,16 @@ +TARGET = post-uninstall +TEMPLATE = app +CONFIG += console qt +QT = core + +SOURCES = \ + main.cpp + +CONFIG(release, debug|release) { + DESTDIR = $$PWD/../../../AmneziaVPN-build/post-uninstall/release + MOC_DIR = $$DESTDIR + OBJECTS_DIR = $$DESTDIR + RCC_DIR = $$DESTDIR +} + +INCLUDEPATH += "$$PWD/../../client" diff --git a/service/buildlib/buildlib.pro b/service/buildlib/buildlib.pro new file mode 100644 index 00000000..1e51cc1d --- /dev/null +++ b/service/buildlib/buildlib.pro @@ -0,0 +1,13 @@ +TEMPLATE=lib +CONFIG += qt dll qtservice-buildlib +mac:CONFIG += absolute_library_soname +win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release build_all +include(../src/qtservice.pri) +TARGET = $$QTSERVICE_LIBNAME +DESTDIR = $$QTSERVICE_LIBDIR +win32 { + DLLDESTDIR = $$[QT_INSTALL_BINS] + QMAKE_DISTCLEAN += $$[QT_INSTALL_BINS]\\$${QTSERVICE_LIBNAME}.dll +} +target.path = $$DESTDIR +INSTALLS += target diff --git a/service/common.pri b/service/common.pri new file mode 100644 index 00000000..d8487537 --- /dev/null +++ b/service/common.pri @@ -0,0 +1,10 @@ +#exists(config.pri):infile(config.pri, SOLUTIONS_LIBRARY, yes): CONFIG += qtservice-uselib +TEMPLATE += fakelib +QTSERVICE_LIBNAME = QtSolutions_Service-head +CONFIG(debug, debug|release) { + mac:QTSERVICE_LIBNAME = $$member(QTSERVICE_LIBNAME, 0)_debug + else:win32:QTSERVICE_LIBNAME = $$member(QTSERVICE_LIBNAME, 0)d +} +TEMPLATE -= fakelib +QTSERVICE_LIBDIR = $$PWD/lib +unix:qtservice-uselib:!qtservice-buildlib:QMAKE_RPATHDIR += $$QTSERVICE_LIBDIR diff --git a/service/server/localserver.cpp b/service/server/localserver.cpp new file mode 100644 index 00000000..e956fd3a --- /dev/null +++ b/service/server/localserver.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "localserver.h" +#include "utils.h" + +LocalServer::LocalServer(QObject *parent) : QObject(parent), + m_clientConnection(nullptr), + m_clientConnected(false) +{ + m_server = new QLocalServer(this); + m_server->setSocketOptions(QLocalServer::WorldAccessOption); + + if (!m_server->listen(Utils::serverName())) { + qDebug() << QString("Unable to start the server: %1.").arg(m_server->errorString()); + return; + } + + connect(m_server, &QLocalServer::newConnection, this, &LocalServer::onNewConnection); + + qDebug().noquote() << QString("Local server started on '%1'").arg(m_server->serverName()); +} + +LocalServer::~LocalServer() +{ + m_clientConnected = false; + m_server->disconnect(); + + QFile::remove(Utils::serverName()); + + qDebug() << "Local server stopped"; +} + +bool LocalServer::isRunning() const +{ + return m_server->isListening(); +} + +void LocalServer::onNewConnection() +{ + if (m_clientConnection) { + m_clientConnection->deleteLater(); + } + + m_clientConnection = m_server->nextPendingConnection(); + connect(m_clientConnection, &QLocalSocket::disconnected, this, &LocalServer::onDisconnected); + m_clientConnected = true; + + qDebug() << "New connection"; + + for(;;) { + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + if (!m_clientConnected || !m_clientConnection) { + break; + } + + if (m_clientConnection->waitForReadyRead(1000) && m_clientConnection->canReadLine()) { + char buf[1024]; + qint64 lineLength = m_clientConnection->readLine(buf, sizeof(buf)); + if (lineLength != -1) { + QString line = buf; + line = line.simplified(); + qDebug().noquote() << QString("Readed line: '%1'").arg(line); + Message icomingMessage(line); + if (!icomingMessage.isValid()) { + qWarning().noquote() << "Message is not valid!"; + continue; + } + + switch (icomingMessage.state()) { + case Message::State::Initialize: + sendMessage(Message(Message::State::Initialize, QStringList({"Server"}))); + break; + case Message::State::StartRequest: + startProcess(icomingMessage.args()); + break; + case Message::State::FinishRequest: + finishProcess(icomingMessage.args()); + break; + default: + ; + } + } + } + } + + qDebug() << "Released"; +} + +void LocalServer::finishProcess(const QStringList& args) +{ + Q_UNUSED(args) +} + +void LocalServer::startProcess(const QStringList& messageArgs) +{ + if (messageArgs.size() < 1) { + return; + } + + QProcess* process = new QProcess(); + connect(process, SIGNAL(started()), this, SLOT(onStarted())); + connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); + + const QString program = messageArgs.at(0); + QStringList args; + for (int i = 1; i < messageArgs.size(); i++) { + args.append(messageArgs.at(i)); + } + + QFileInfo fi(program); + const QString baseName = fi.baseName(); + if (!fi.exists()) { + qWarning() << "This program does not exist"; + sendMessage(Message(Message::State::Started, QStringList({baseName}))); + sendMessage(Message(Message::State::Finished, QStringList({baseName, QString::number(-1)}))); + return; + } + + process->setObjectName(baseName); + + qDebug().noquote() << QString("Start process '%1' - '%2' with args '%3'") + .arg(baseName).arg(program).arg(args.join(",")); + + process->start(program, args); + m_processList.append(process); +} + +void LocalServer::onFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + Q_UNUSED(exitStatus) + + QProcess* process = (QProcess*)sender(); + sendMessage(Message(Message::State::Finished, QStringList({process->objectName(), QString::number(exitCode)}))); +} + +void LocalServer::onStarted() +{ + QProcess* process = (QProcess*)sender(); + sendMessage(Message(Message::State::Started, QStringList({process->objectName()}))); +} + +void LocalServer::onDisconnected() +{ + if (!m_clientConnected) { + return; + } + + m_clientConnected = false; + QLocalSocket* clientConnection = (QLocalSocket*)sender(); + clientConnection->deleteLater(); + + qDebug() << "Diconnected"; +} + +void LocalServer::sendMessage(const Message& message) +{ + if (!m_clientConnection || !m_clientConnected) { + qDebug()<< "Cannot send data, remote peer is not connected"; + return; + } + + const QString data = message.toString(); + bool status = m_clientConnection->write(QString(data + "\n").toUtf8()); + + qDebug().noquote() << QString("Send message '%1', status '%2'").arg(data).arg(Utils::toString(status)); +} + diff --git a/service/server/localserver.h b/service/server/localserver.h new file mode 100644 index 00000000..d68d121e --- /dev/null +++ b/service/server/localserver.h @@ -0,0 +1,43 @@ +#ifndef LOCALSERVER_H +#define LOCALSERVER_H + +#include +#include +#include +#include + +#include "message.h" + +class QLocalServer; +class QLocalSocket; +class QProcess; + +class LocalServer : public QObject +{ + Q_OBJECT + +public: + explicit LocalServer(QObject* parent = nullptr); + ~LocalServer(); + + bool isRunning() const; + +protected slots: + void onDisconnected(); + void onNewConnection(); + + void onFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onStarted(); + +private: + void finishProcess(const QStringList& messageArgs); + void sendMessage(const Message& message); + void startProcess(const QStringList& messageArgs); + + QLocalServer* m_server; + QLocalSocket* m_clientConnection; + QVector m_processList; + bool m_clientConnected; +}; + +#endif // LOCALSERVER_H diff --git a/service/server/log.cpp b/service/server/log.cpp new file mode 100644 index 00000000..9d0d3a72 --- /dev/null +++ b/service/server/log.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include + +#include "log.h" +#include "defines.h" +#include "utils.h" + +QFile Log::m_file; +QTextStream Log::m_textStream; +QString Log::m_logFileName; + +void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + if (msg.simplified().isEmpty()) { + return; + } + + Log::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush; + + std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; +} + +bool Log::initialize() +{ + QString path = Utils::systemLogPath(); + QDir appDir(path); + if (!appDir.mkpath(path)) { + return false; + } + + m_logFileName = QString("%1.log").arg(SERVICE_NAME); + + qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}"); + + m_file.setFileName(appDir.filePath(m_logFileName)); + if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "Cannot open log file:" << m_logFileName; + return false; + } + m_file.setTextModeEnabled(true); + m_textStream.setDevice(&m_file); + qInstallMessageHandler(debugMessageHandler); + + return true; +} + +QString Log::serviceLogFileNamePath() +{ + return m_file.fileName(); +} + diff --git a/service/server/log.h b/service/server/log.h new file mode 100644 index 00000000..1c385f7a --- /dev/null +++ b/service/server/log.h @@ -0,0 +1,23 @@ +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +class Log +{ +public: + static bool initialize(); + static QString serviceLogFileNamePath(); + +private: + friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + + static QFile m_file; + static QString m_logFileName; + static QTextStream m_textStream; +}; + +#endif // LOG_H diff --git a/service/server/main.cpp b/service/server/main.cpp new file mode 100644 index 00000000..65be5e52 --- /dev/null +++ b/service/server/main.cpp @@ -0,0 +1,42 @@ +#include + +#include "defines.h" +#include "localserver.h" +#include "log.h" +#include "systemservice.h" +#include "utils.h" + +int runApplication(int argc, char** argv) +{ + QCoreApplication app(argc,argv); + LocalServer localServer; + if (!localServer.isRunning()) { + return -1; + } + return app.exec(); +} +int main(int argc, char **argv) +{ + Utils::initializePath(Utils::systemLogPath()); + + Log::initialize(); + + if (argc == 2) { + qInfo() << "Started as console application"; + return runApplication(argc, argv); + } else { + qInfo() << "Started as system service"; +#ifdef Q_OS_WIN + SystemService systemService(argc, argv); + return systemService.exec(); + +#else + //daemon(0,0); + return runApplication(argc, argv); +#endif + + } + + // Never reached + return 0; +} diff --git a/service/server/server.pro b/service/server/server.pro new file mode 100644 index 00000000..9b35d7af --- /dev/null +++ b/service/server/server.pro @@ -0,0 +1,30 @@ +TARGET = AmneziaVPN-service +TEMPLATE = app +CONFIG += console qt no_batch +QT += core network + +HEADERS = \ + ../../client/message.h \ + ../../client/utils.h \ + localserver.h \ + log.h \ + systemservice.h + +SOURCES = \ + ../../client/message.cpp \ + ../../client/utils.cpp \ + localserver.cpp \ + log.cpp \ + main.cpp \ + systemservice.cpp + +include(../src/qtservice.pri) + +CONFIG(release, debug|release) { + DESTDIR = $$PWD/../../../AmneziaVPN-build/server/release + MOC_DIR = $$DESTDIR + OBJECTS_DIR = $$DESTDIR + RCC_DIR = $$DESTDIR +} + +INCLUDEPATH += "$$PWD/../../client" diff --git a/service/server/systemservice.cpp b/service/server/systemservice.cpp new file mode 100644 index 00000000..32a7f86f --- /dev/null +++ b/service/server/systemservice.cpp @@ -0,0 +1,24 @@ +#include "defines.h" +#include "localserver.h" +#include "systemservice.h" + +SystemService::SystemService(int argc, char **argv) + : QtService(argc, argv, SERVICE_NAME) +{ + setServiceDescription("Service for AmneziaVPN"); +} + +void SystemService::start() +{ + QCoreApplication* app = application(); + m_localServer = new LocalServer(); + + if (!m_localServer->isRunning()) { + app->quit(); + } +} + +void SystemService::stop() +{ + delete m_localServer; +} diff --git a/service/server/systemservice.h b/service/server/systemservice.h new file mode 100644 index 00000000..26ffde69 --- /dev/null +++ b/service/server/systemservice.h @@ -0,0 +1,24 @@ +#ifndef SYSTEMSERVICE_H +#define SYSTEMSERVICE_H + +#include + +#include "qtservice.h" + +class LocalServer; + +class SystemService : public QtService +{ + +public: + SystemService(int argc, char** argv); + +protected: + void start() override; + void stop() override; + +private: + LocalServer* m_localServer; +}; + +#endif // SYSTEMSERVICE_H diff --git a/service/service.pro b/service/service.pro new file mode 100644 index 00000000..8b08654f --- /dev/null +++ b/service/service.pro @@ -0,0 +1,5 @@ +TEMPLATE=subdirs +CONFIG += ordered +include(common.pri) +qtservice-uselib:SUBDIRS=buildlib +SUBDIRS+=server diff --git a/service/src/QtService b/service/src/QtService new file mode 100644 index 00000000..57e17a52 --- /dev/null +++ b/service/src/QtService @@ -0,0 +1 @@ +#include "qtservice.h" diff --git a/service/src/QtServiceBase b/service/src/QtServiceBase new file mode 100644 index 00000000..57e17a52 --- /dev/null +++ b/service/src/QtServiceBase @@ -0,0 +1 @@ +#include "qtservice.h" diff --git a/service/src/QtServiceController b/service/src/QtServiceController new file mode 100644 index 00000000..57e17a52 --- /dev/null +++ b/service/src/QtServiceController @@ -0,0 +1 @@ +#include "qtservice.h" diff --git a/service/src/qtservice.cpp b/service/src/qtservice.cpp new file mode 100644 index 00000000..5eae058e --- /dev/null +++ b/service/src/qtservice.cpp @@ -0,0 +1,1129 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtservice.h" +#include "qtservice_p.h" +#include +#include +#include +#include +#include + +#if defined(QTSERVICE_DEBUG) +#include +#include +#include +#include +#include +#if defined(Q_OS_WIN32) +#include +#else +#include +#include +#endif + +static QFile* f = 0; + +static void qtServiceCloseDebugLog() +{ + if (!f) + return; + f->write(QTime::currentTime().toString("HH:mm:ss.zzz").toLatin1()); + f->write(" --- DEBUG LOG CLOSED ---\n\n"); + f->flush(); + f->close(); + delete f; + f = 0; +} + +#if QT_VERSION >= 0x050000 +void qtServiceLogDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg) +#else +void qtServiceLogDebug(QtMsgType type, const char* msg) +#endif +{ + static QMutex mutex; + QMutexLocker locker(&mutex); +#if defined(Q_OS_WIN32) + const qulonglong processId = GetCurrentProcessId(); +#else + const qulonglong processId = getpid(); +#endif + QByteArray s(QTime::currentTime().toString("HH:mm:ss.zzz").toLatin1()); + s += " ["; + s += QByteArray::number(processId); + s += "] "; + + if (!f) { +#if defined(Q_OS_WIN32) + f = new QFile("c:/service-debuglog.txt"); +#else + f = new QFile("/tmp/service-debuglog.txt"); +#endif + if (!f->open(QIODevice::WriteOnly | QIODevice::Append)) { + delete f; + f = 0; + return; + } + QByteArray ps('\n' + s + "--- DEBUG LOG OPENED ---\n"); + f->write(ps); + } + + switch (type) { + case QtWarningMsg: + s += "WARNING: "; + break; + case QtCriticalMsg: + s += "CRITICAL: "; + break; + case QtFatalMsg: + s+= "FATAL: "; + break; + case QtDebugMsg: + s += "DEBUG: "; + break; + default: + // Nothing + break; + } + +#if QT_VERSION >= 0x050400 + s += qFormatLogMessage(type, context, msg).toLocal8Bit(); +#elif QT_VERSION >= 0x050000 + s += msg.toLocal8Bit(); + Q_UNUSED(context) +#else + s += msg; +#endif + s += '\n'; + + f->write(s); + f->flush(); + + if (type == QtFatalMsg) { + qtServiceCloseDebugLog(); + exit(1); + } +} + +#endif + +/*! + \class QtServiceController + + \brief The QtServiceController class allows you to control + services from separate applications. + + QtServiceController provides a collection of functions that lets + you install and run a service controlling its execution, as well + as query its status. + + In order to run a service, the service must be installed in the + system's service database using the install() function. The system + will start the service depending on the specified StartupType; it + can either be started during system startup, or when a process + starts it manually. + + Once a service is installed, the service can be run and controlled + manually using the start(), stop(), pause(), resume() or + sendCommand() functions. You can at any time query for the + service's status using the isInstalled() and isRunning() + functions, or you can query its properties using the + serviceDescription(), serviceFilePath(), serviceName() and + startupType() functions. For example: + + \code + MyService service; \\ which inherits QtService + QString serviceFilePath; + + QtServiceController controller(service.serviceName()); + + if (controller.install(serviceFilePath)) + controller.start() + + if (controller.isRunning()) + QMessageBox::information(this, tr("Service Status"), + tr("The %1 service is started").arg(controller.serviceName())); + + ... + + controller.stop(); + controller.uninstall(); + } + \endcode + + An instance of the service controller can only control one single + service. To control several services within one application, you + must create en equal number of service controllers. + + The QtServiceController destructor neither stops nor uninstalls + the associated service. To stop a service the stop() function must + be called explicitly. To uninstall a service, you can use the + uninstall() function. + + \sa QtServiceBase, QtService +*/ + +/*! + \enum QtServiceController::StartupType + This enum describes when a service should be started. + + \value AutoStartup The service is started during system startup. + \value ManualStartup The service must be started manually by a process. + + \warning The \a StartupType enum is ignored under UNIX-like + systems. A service, or daemon, can only be started manually on such + systems with current implementation. + + \sa startupType() +*/ + + +/*! + Creates a controller object for the service with the given + \a name. +*/ +QtServiceController::QtServiceController(const QString &name) + : d_ptr(new QtServiceControllerPrivate()) +{ + Q_D(QtServiceController); + d->q_ptr = this; + d->serviceName = name; +} +/*! + Destroys the service controller. This neither stops nor uninstalls + the controlled service. + + To stop a service the stop() function must be called + explicitly. To uninstall a service, you can use the uninstall() + function. + + \sa stop(), QtServiceController::uninstall() +*/ +QtServiceController::~QtServiceController() +{ + delete d_ptr; +} +/*! + \fn bool QtServiceController::isInstalled() const + + Returns true if the service is installed; otherwise returns false. + + On Windows it uses the system's service control manager. + + On Unix it checks configuration written to QSettings::SystemScope + using "QtSoftware" as organization name. + + \sa install() +*/ + +/*! + \fn bool QtServiceController::isRunning() const + + Returns true if the service is running; otherwise returns false. A + service must be installed before it can be run using a controller. + + \sa start(), isInstalled() +*/ + +/*! + Returns the name of the controlled service. + + \sa QtServiceController(), serviceDescription() +*/ +QString QtServiceController::serviceName() const +{ + Q_D(const QtServiceController); + return d->serviceName; +} +/*! + \fn QString QtServiceController::serviceDescription() const + + Returns the description of the controlled service. + + \sa install(), serviceName() +*/ + +/*! + \fn QtServiceController::StartupType QtServiceController::startupType() const + + Returns the startup type of the controlled service. + + \sa install(), serviceName() +*/ + +/*! + \fn QString QtServiceController::serviceFilePath() const + + Returns the file path to the controlled service. + + \sa install(), serviceName() +*/ + +/*! + Installs the service with the given \a serviceFilePath + and returns true if the service is installed + successfully; otherwise returns false. + + On Windows service is installed in the system's service control manager with the given + \a account and \a password. + + On Unix service configuration is written to QSettings::SystemScope + using "QtSoftware" as organization name. \a account and \a password + arguments are ignored. + + \warning Due to the different implementations of how services (daemons) + are installed on various UNIX-like systems, this method doesn't + integrate the service into the system's startup scripts. + + \sa uninstall(), start() +*/ +bool QtServiceController::install(const QString &serviceFilePath, const QString &account, + const QString &password) +{ + QStringList arguments; + arguments << QLatin1String("-i"); + arguments << account; + arguments << password; + return (QProcess::execute(serviceFilePath, arguments) == 0); +} + + +/*! + \fn bool QtServiceController::uninstall() + + Uninstalls the service and returns true if successful; otherwise returns false. + + On Windows service is uninstalled using the system's service control manager. + + On Unix service configuration is cleared using QSettings::SystemScope + with "QtSoftware" as organization name. + + + \sa install() +*/ + +/*! + \fn bool QtServiceController::start(const QStringList &arguments) + + Starts the installed service passing the given \a arguments to the + service. A service must be installed before a controller can run it. + + Returns true if the service could be started; otherwise returns + false. + + \sa install(), stop() +*/ + +/*! + \overload + + Starts the installed service without passing any arguments to the service. +*/ +bool QtServiceController::start() +{ + return start(QStringList()); +} + +/*! + \fn bool QtServiceController::stop() + + Requests the running service to stop. The service will call the + QtServiceBase::stop() implementation unless the service's state + is QtServiceBase::CannotBeStopped. This function does nothing if + the service is not running. + + Returns true if a running service was successfully stopped; + otherwise false. + + \sa start(), QtServiceBase::stop(), QtServiceBase::ServiceFlags +*/ + +/*! + \fn bool QtServiceController::pause() + + Requests the running service to pause. If the service's state is + QtServiceBase::CanBeSuspended, the service will call the + QtServiceBase::pause() implementation. The function does nothing + if the service is not running. + + Returns true if a running service was successfully paused; + otherwise returns false. + + \sa resume(), QtServiceBase::pause(), QtServiceBase::ServiceFlags +*/ + +/*! + \fn bool QtServiceController::resume() + + Requests the running service to continue. If the service's state + is QtServiceBase::CanBeSuspended, the service will call the + QtServiceBase::resume() implementation. This function does nothing + if the service is not running. + + Returns true if a running service was successfully resumed; + otherwise returns false. + + \sa pause(), QtServiceBase::resume(), QtServiceBase::ServiceFlags +*/ + +/*! + \fn bool QtServiceController::sendCommand(int code) + + Sends the user command \a code to the service. The service will + call the QtServiceBase::processCommand() implementation. This + function does nothing if the service is not running. + + Returns true if the request was sent to a running service; + otherwise returns false. + + \sa QtServiceBase::processCommand() +*/ + +class QtServiceStarter : public QObject +{ + Q_OBJECT +public: + QtServiceStarter(QtServiceBasePrivate *service) + : QObject(), d_ptr(service) {} +public slots: + void slotStart() + { + d_ptr->startService(); + } +private: + QtServiceBasePrivate *d_ptr; +}; +#include "qtservice.moc" + +QtServiceBase *QtServiceBasePrivate::instance = 0; + +QtServiceBasePrivate::QtServiceBasePrivate(const QString &name) + : startupType(QtServiceController::ManualStartup), serviceFlags(0), controller(name) +{ + +} + +QtServiceBasePrivate::~QtServiceBasePrivate() +{ + +} + +void QtServiceBasePrivate::startService() +{ + q_ptr->start(); +} + +int QtServiceBasePrivate::run(bool asService, const QStringList &argList) +{ + int argc = argList.size(); + QVector argv(argc); + QList argvData; + for (int i = 0; i < argc; ++i) + argvData.append(argList.at(i).toLocal8Bit()); + for (int i = 0; i < argc; ++i) + argv[i] = argvData[i].data(); + + if (asService && !sysInit()) + return -1; + + q_ptr->createApplication(argc, argv.data()); + QCoreApplication *app = QCoreApplication::instance(); + if (!app) + return -1; + + if (asService) + sysSetPath(); + + QtServiceStarter starter(this); + QTimer::singleShot(0, &starter, SLOT(slotStart())); + int res = q_ptr->executeApplication(); + delete app; + + if (asService) + sysCleanup(); + return res; +} + + +/*! + \class QtServiceBase + + \brief The QtServiceBase class provides an API for implementing + Windows services and Unix daemons. + + A Windows service or Unix daemon (a "service"), is a program that + runs "in the background" independently of whether a user is logged + in or not. A service is often set up to start when the machine + boots up, and will typically run continuously as long as the + machine is on. + + Services are usually non-interactive console applications. User + interaction, if required, is usually implemented in a separate, + normal GUI application that communicates with the service through + an IPC channel. For simple communication, + QtServiceController::sendCommand() and QtService::processCommand() + may be used, possibly in combination with a shared settings + file. For more complex, interactive communication, a custom IPC + channel should be used, e.g. based on Qt's networking classes. (In + certain circumstances, a service may provide a GUI itself, + ref. the "interactive" example documentation). + + Typically, you will create a service by subclassing the QtService + template class which inherits QtServiceBase and allows you to + create a service for a particular application type. + + The Windows implementation uses the NT Service Control Manager, + and the application can be controlled through the system + administration tools. Services are usually launched using the + system account, which requires that all DLLs that the service + executable depends on (i.e. Qt), are located in the same directory + as the service, or in a system path. + + On Unix a service is implemented as a daemon. + + You can retrieve the service's description, state, and startup + type using the serviceDescription(), serviceFlags() and + startupType() functions respectively. The service's state is + decribed by the ServiceFlag enum. The mentioned properites can + also be set using the corresponding set functions. In addition you + can retrieve the service's name using the serviceName() function. + + Several of QtServiceBase's protected functions are called on + requests from the QtServiceController class: + + \list + \o start() + \o pause() + \o processCommand() + \o resume() + \o stop() + \endlist + + You can control any given service using an instance of the + QtServiceController class which also allows you to control + services from separate applications. The mentioned functions are + all virtual and won't do anything unless they are + reimplemented. You can reimplement these functions to pause and + resume the service's execution, as well as process user commands + and perform additional clean-ups before shutting down. + + QtServiceBase also provides the static instance() function which + returns a pointer to an application's QtServiceBase instance. In + addition, a service can report events to the system's event log + using the logMessage() function. The MessageType enum describes + the different types of messages a service reports. + + The implementation of a service application's main function + typically creates an service object derived by subclassing the + QtService template class. Then the main function will call this + service's exec() function, and return the result of that call. For + example: + + \code + int main(int argc, char **argv) + { + MyService service(argc, argv); + return service.exec(); + } + \endcode + + When the exec() function is called, it will parse the service + specific arguments passed in \c argv, perform the required + actions, and return. + + \target serviceSpecificArguments + + The following arguments are recognized as service specific: + + \table + \header \i Short \i Long \i Explanation + \row \i -i \i -install \i Install the service. + \row \i -u \i -uninstall \i Uninstall the service. + \row \i -e \i -exec + \i Execute the service as a standalone application (useful for debug purposes). + This is a blocking call, the service will be executed like a normal application. + In this mode you will not be able to communicate with the service from the contoller. + \row \i -t \i -terminate \i Stop the service. + \row \i -p \i -pause \i Pause the service. + \row \i -r \i -resume \i Resume a paused service. + \row \i -c \e{cmd} \i -command \e{cmd} + \i Send the user defined command code \e{cmd} to the service application. + \row \i -v \i -version \i Display version and status information. + \endtable + + If \e none of the arguments is recognized as service specific, + exec() will first call the createApplication() function, then + executeApplication() and finally the start() function. In the end, + exec() returns while the service continues in its own process + waiting for commands from the service controller. + + \sa QtService, QtServiceController +*/ + +/*! + \enum QtServiceBase::MessageType + + This enum describes the different types of messages a service + reports to the system log. + + \value Success An operation has succeeded, e.g. the service + is started. + \value Error An operation failed, e.g. the service failed to start. + \value Warning An operation caused a warning that might require user + interaction. + \value Information Any type of usually non-critical information. +*/ + +/*! + \enum QtServiceBase::ServiceFlag + + This enum describes the different capabilities of a service. + + \value Default The service can be stopped, but not suspended. + \value CanBeSuspended The service can be suspended. + \value CannotBeStopped The service cannot be stopped. + \value NeedsStopOnShutdown (Windows only) The service will be stopped before the system shuts down. Note that Microsoft recommends this only for services that must absolutely clean up during shutdown, because there is a limited time available for shutdown of services. +*/ + +/*! + Creates a service instance called \a name. The \a argc and \a argv + parameters are parsed after the exec() function has been + called. Then they are passed to the application's constructor. + The application type is determined by the QtService subclass. + + The service is neither installed nor started. The name must not + contain any backslashes or be longer than 255 characters. In + addition, the name must be unique in the system's service + database. + + \sa exec(), start(), QtServiceController::install() +*/ +QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name) +{ +#if defined(QTSERVICE_DEBUG) +# if QT_VERSION >= 0x050000 + qInstallMessageHandler(qtServiceLogDebug); +# else + qInstallMsgHandler(qtServiceLogDebug); +# endif + qAddPostRoutine(qtServiceCloseDebugLog); +#endif + + Q_ASSERT(!QtServiceBasePrivate::instance); + QtServiceBasePrivate::instance = this; + + QString nm(name); + if (nm.length() > 255) { + qWarning("QtService: 'name' is longer than 255 characters."); + nm.truncate(255); + } + if (nm.contains('\\')) { + qWarning("QtService: 'name' contains backslashes '\\'."); + nm.replace((QChar)'\\', (QChar)'\0'); + } + + d_ptr = new QtServiceBasePrivate(nm); + d_ptr->q_ptr = this; + + d_ptr->serviceFlags = 0; + d_ptr->sysd = 0; + for (int i = 0; i < argc; ++i) + d_ptr->args.append(QString::fromLocal8Bit(argv[i])); +} + +/*! + Destroys the service object. This neither stops nor uninstalls the + service. + + To stop a service the stop() function must be called + explicitly. To uninstall a service, you can use the + QtServiceController::uninstall() function. + + \sa stop(), QtServiceController::uninstall() +*/ +QtServiceBase::~QtServiceBase() +{ + delete d_ptr; + QtServiceBasePrivate::instance = 0; +} + +/*! + Returns the name of the service. + + \sa QtServiceBase(), serviceDescription() +*/ +QString QtServiceBase::serviceName() const +{ + return d_ptr->controller.serviceName(); +} + +/*! + Returns the description of the service. + + \sa setServiceDescription(), serviceName() +*/ +QString QtServiceBase::serviceDescription() const +{ + return d_ptr->serviceDescription; +} + +/*! + Sets the description of the service to the given \a description. + + \sa serviceDescription() +*/ +void QtServiceBase::setServiceDescription(const QString &description) +{ + d_ptr->serviceDescription = description; +} + +/*! + Returns the service's startup type. + + \sa QtServiceController::StartupType, setStartupType() +*/ +QtServiceController::StartupType QtServiceBase::startupType() const +{ + return d_ptr->startupType; +} + +/*! + Sets the service's startup type to the given \a type. + + \sa QtServiceController::StartupType, startupType() +*/ +void QtServiceBase::setStartupType(QtServiceController::StartupType type) +{ + d_ptr->startupType = type; +} + +/*! + Returns the service's state which is decribed using the + ServiceFlag enum. + + \sa ServiceFlags, setServiceFlags() +*/ +QtServiceBase::ServiceFlags QtServiceBase::serviceFlags() const +{ + return d_ptr->serviceFlags; +} + +/*! + \fn void QtServiceBase::setServiceFlags(ServiceFlags flags) + + Sets the service's state to the state described by the given \a + flags. + + \sa ServiceFlags, serviceFlags() +*/ + +/*! + Executes the service. + + When the exec() function is called, it will parse the \l + {serviceSpecificArguments} {service specific arguments} passed in + \c argv, perform the required actions, and exit. + + If none of the arguments is recognized as service specific, exec() + will first call the createApplication() function, then executeApplication() and + finally the start() function. In the end, exec() + returns while the service continues in its own process waiting for + commands from the service controller. + + \sa QtServiceController +*/ +int QtServiceBase::exec() +{ + if (d_ptr->args.size() > 1) { + QString a = d_ptr->args.at(1); + if (a == QLatin1String("-i") || a == QLatin1String("-install")) { + if (!d_ptr->controller.isInstalled()) { + QString account; + QString password; + if (d_ptr->args.size() > 2) + account = d_ptr->args.at(2); + if (d_ptr->args.size() > 3) + password = d_ptr->args.at(3); + if (!d_ptr->install(account, password)) { + fprintf(stderr, "The service %s could not be installed\n", serviceName().toLatin1().constData()); + return -1; + } else { + printf("The service %s has been installed under: %s\n", + serviceName().toLatin1().constData(), d_ptr->filePath().toLatin1().constData()); + } + } else { + fprintf(stderr, "The service %s is already installed\n", serviceName().toLatin1().constData()); + } + return 0; + } else if (a == QLatin1String("-u") || a == QLatin1String("-uninstall")) { + if (d_ptr->controller.isInstalled()) { + if (!d_ptr->controller.uninstall()) { + fprintf(stderr, "The service %s could not be uninstalled\n", serviceName().toLatin1().constData()); + return -1; + } else { + printf("The service %s has been uninstalled.\n", + serviceName().toLatin1().constData()); + } + } else { + fprintf(stderr, "The service %s is not installed\n", serviceName().toLatin1().constData()); + } + return 0; + } else if (a == QLatin1String("-v") || a == QLatin1String("-version")) { + printf("The service\n" + "\t%s\n\t%s\n\n", serviceName().toLatin1().constData(), d_ptr->args.at(0).toLatin1().constData()); + printf("is %s", (d_ptr->controller.isInstalled() ? "installed" : "not installed")); + printf(" and %s\n\n", (d_ptr->controller.isRunning() ? "running" : "not running")); + return 0; + } else if (a == QLatin1String("-e") || a == QLatin1String("-exec")) { + d_ptr->args.removeAt(1); + int ec = d_ptr->run(false, d_ptr->args); + if (ec == -1) + qErrnoWarning("The service could not be executed."); + return ec; + } else if (a == QLatin1String("-t") || a == QLatin1String("-terminate")) { + if (!d_ptr->controller.stop()) + qErrnoWarning("The service could not be stopped."); + return 0; + } else if (a == QLatin1String("-p") || a == QLatin1String("-pause")) { + d_ptr->controller.pause(); + return 0; + } else if (a == QLatin1String("-r") || a == QLatin1String("-resume")) { + d_ptr->controller.resume(); + return 0; + } else if (a == QLatin1String("-c") || a == QLatin1String("-command")) { + int code = 0; + if (d_ptr->args.size() > 2) + code = d_ptr->args.at(2).toInt(); + d_ptr->controller.sendCommand(code); + return 0; + } else if (a == QLatin1String("-h") || a == QLatin1String("-help")) { + printf("\n%s -[i|u|e|t|p|r|c|v|h]\n" + "\t-i(nstall) [account] [password]\t: Install the service, optionally using given account and password\n" + "\t-u(ninstall)\t: Uninstall the service.\n" + "\t-e(xec)\t\t: Run as a regular application. Useful for debugging.\n" + "\t-t(erminate)\t: Stop the service.\n" + "\t-p(ause)\t: Pause the service.\n" + "\t-r(esume)\t: Resume a paused service.\n" + "\t-c(ommand) num\t: Send command code num to the service.\n" + "\t-v(ersion)\t: Print version and status information.\n" + "\t-h(elp) \t: Show this help\n" + "\tNo arguments\t: Start the service.\n", + d_ptr->args.at(0).toLatin1().constData()); + return 0; + } + } +#if defined(Q_OS_UNIX) + if (::getenv("QTSERVICE_RUN")) { + // Means we're the detached, real service process. + int ec = d_ptr->run(true, d_ptr->args); + if (ec == -1) + qErrnoWarning("The service failed to run."); + return ec; + } +#endif + if (!d_ptr->start()) { + fprintf(stderr, "The service %s could not start\n", serviceName().toLatin1().constData()); + return -4; + } + return 0; +} + +/*! + \fn void QtServiceBase::logMessage(const QString &message, MessageType type, + int id, uint category, const QByteArray &data) + + Reports a message of the given \a type with the given \a message + to the local system event log. The message identifier \a id and + the message \a category are user defined values. The \a data + parameter can contain arbitrary binary data. + + Message strings for \a id and \a category must be provided by a + message file, which must be registered in the system registry. + Refer to the MSDN for more information about how to do this on + Windows. + + \sa MessageType +*/ + +/*! + Returns a pointer to the current application's QtServiceBase + instance. +*/ +QtServiceBase *QtServiceBase::instance() +{ + return QtServiceBasePrivate::instance; +} + +/*! + \fn void QtServiceBase::start() + + This function must be implemented in QtServiceBase subclasses in + order to perform the service's work. Usually you create some main + object on the heap which is the heart of your service. + + The function is only called when no service specific arguments + were passed to the service constructor, and is called by exec() + after it has called the executeApplication() function. + + Note that you \e don't need to create an application object or + call its exec() function explicitly. + + \sa exec(), stop(), QtServiceController::start() +*/ + +/*! + Reimplement this function to perform additional cleanups before + shutting down (for example deleting a main object if it was + created in the start() function). + + This function is called in reply to controller requests. The + default implementation does nothing. + + \sa start(), QtServiceController::stop() +*/ +void QtServiceBase::stop() +{ +} + +/*! + Reimplement this function to pause the service's execution (for + example to stop a polling timer, or to ignore socket notifiers). + + This function is called in reply to controller requests. The + default implementation does nothing. + + \sa resume(), QtServiceController::pause() +*/ +void QtServiceBase::pause() +{ +} + +/*! + Reimplement this function to continue the service after a call to + pause(). + + This function is called in reply to controller requests. The + default implementation does nothing. + + \sa pause(), QtServiceController::resume() +*/ +void QtServiceBase::resume() +{ +} + +/*! + Reimplement this function to process the user command \a code. + + + This function is called in reply to controller requests. The + default implementation does nothing. + + \sa QtServiceController::sendCommand() +*/ +void QtServiceBase::processCommand(int /*code*/) +{ +} + +/*! + \fn void QtServiceBase::createApplication(int &argc, char **argv) + + Creates the application object using the \a argc and \a argv + parameters. + + This function is only called when no \l + {serviceSpecificArguments}{service specific arguments} were + passed to the service constructor, and is called by exec() before + it calls the executeApplication() and start() functions. + + The createApplication() function is implemented in QtService, but + you might want to reimplement it, for example, if the chosen + application type's constructor needs additional arguments. + + \sa exec(), QtService +*/ + +/*! + \fn int QtServiceBase::executeApplication() + + Executes the application previously created with the + createApplication() function. + + This function is only called when no \l + {serviceSpecificArguments}{service specific arguments} were + passed to the service constructor, and is called by exec() after + it has called the createApplication() function and before start() function. + + This function is implemented in QtService. + + \sa exec(), createApplication() +*/ + +/*! + \class QtService + + \brief The QtService is a convenient template class that allows + you to create a service for a particular application type. + + A Windows service or Unix daemon (a "service"), is a program that + runs "in the background" independently of whether a user is logged + in or not. A service is often set up to start when the machine + boots up, and will typically run continuously as long as the + machine is on. + + Services are usually non-interactive console applications. User + interaction, if required, is usually implemented in a separate, + normal GUI application that communicates with the service through + an IPC channel. For simple communication, + QtServiceController::sendCommand() and QtService::processCommand() + may be used, possibly in combination with a shared settings file. For + more complex, interactive communication, a custom IPC channel + should be used, e.g. based on Qt's networking classes. (In certain + circumstances, a service may provide a GUI itself, ref. the + "interactive" example documentation). + + \bold{Note:} On Unix systems, this class relies on facilities + provided by the QtNetwork module, provided as part of the + \l{Qt Open Source Edition} and certain \l{Qt Commercial Editions}. + + The QtService class functionality is inherited from QtServiceBase, + but in addition the QtService class binds an instance of + QtServiceBase with an application type. + + Typically, you will create a service by subclassing the QtService + template class. For example: + + \code + class MyService : public QtService + { + public: + MyService(int argc, char **argv); + ~MyService(); + + protected: + void start(); + void stop(); + void pause(); + void resume(); + void processCommand(int code); + }; + \endcode + + The application type can be QCoreApplication for services without + GUI, QApplication for services with GUI or you can use your own + custom application type. + + You must reimplement the QtServiceBase::start() function to + perform the service's work. Usually you create some main object on + the heap which is the heart of your service. + + In addition, you might want to reimplement the + QtServiceBase::pause(), QtServiceBase::processCommand(), + QtServiceBase::resume() and QtServiceBase::stop() to intervene the + service's process on controller requests. You can control any + given service using an instance of the QtServiceController class + which also allows you to control services from separate + applications. The mentioned functions are all virtual and won't do + anything unless they are reimplemented. + + Your custom service is typically instantiated in the application's + main function. Then the main function will call your service's + exec() function, and return the result of that call. For example: + + \code + int main(int argc, char **argv) + { + MyService service(argc, argv); + return service.exec(); + } + \endcode + + When the exec() function is called, it will parse the \l + {serviceSpecificArguments} {service specific arguments} passed in + \c argv, perform the required actions, and exit. + + If none of the arguments is recognized as service specific, exec() + will first call the createApplication() function, then executeApplication() and + finally the start() function. In the end, exec() + returns while the service continues in its own process waiting for + commands from the service controller. + + \sa QtServiceBase, QtServiceController +*/ + +/*! + \fn QtService::QtService(int argc, char **argv, const QString &name) + + Constructs a QtService object called \a name. The \a argc and \a + argv parameters are parsed after the exec() function has been + called. Then they are passed to the application's constructor. + + There can only be one QtService object in a process. + + \sa QtServiceBase() +*/ + +/*! + \fn QtService::~QtService() + + Destroys the service object. +*/ + +/*! + \fn Application *QtService::application() const + + Returns a pointer to the application object. +*/ + +/*! + \fn void QtService::createApplication(int &argc, char **argv) + + Creates application object of type Application passing \a argc and + \a argv to its constructor. + + \reimp + +*/ + +/*! + \fn int QtService::executeApplication() + + \reimp +*/ diff --git a/service/src/qtservice.h b/service/src/qtservice.h new file mode 100644 index 00000000..01d5b07f --- /dev/null +++ b/service/src/qtservice.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSERVICE_H +#define QTSERVICE_H + +#include + +#if defined(Q_OS_WIN) +# if !defined(QT_QTSERVICE_EXPORT) && !defined(QT_QTSERVICE_IMPORT) +# define QT_QTSERVICE_EXPORT +# elif defined(QT_QTSERVICE_IMPORT) +# if defined(QT_QTSERVICE_EXPORT) +# undef QT_QTSERVICE_EXPORT +# endif +# define QT_QTSERVICE_EXPORT __declspec(dllimport) +# elif defined(QT_QTSERVICE_EXPORT) +# undef QT_QTSERVICE_EXPORT +# define QT_QTSERVICE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTSERVICE_EXPORT +#endif + +class QStringList; +class QtServiceControllerPrivate; + +class QT_QTSERVICE_EXPORT QtServiceController +{ + Q_DECLARE_PRIVATE(QtServiceController) +public: + enum StartupType + { + AutoStartup = 0, ManualStartup + }; + + QtServiceController(const QString &name); + virtual ~QtServiceController(); + + bool isInstalled() const; + bool isRunning() const; + + QString serviceName() const; + QString serviceDescription() const; + StartupType startupType() const; + QString serviceFilePath() const; + + static bool install(const QString &serviceFilePath, const QString &account = QString(), + const QString &password = QString()); + bool uninstall(); + + bool start(const QStringList &arguments); + bool start(); + bool stop(); + bool pause(); + bool resume(); + bool sendCommand(int code); + +private: + QtServiceControllerPrivate *d_ptr; +}; + +class QtServiceBasePrivate; + +class QT_QTSERVICE_EXPORT QtServiceBase +{ + Q_DECLARE_PRIVATE(QtServiceBase) +public: + + enum MessageType + { + Success = 0, Error, Warning, Information + }; + + enum ServiceFlag + { + Default = 0x00, + CanBeSuspended = 0x01, + CannotBeStopped = 0x02, + NeedsStopOnShutdown = 0x04 + }; + + Q_DECLARE_FLAGS(ServiceFlags, ServiceFlag) + + QtServiceBase(int argc, char **argv, const QString &name); + virtual ~QtServiceBase(); + + QString serviceName() const; + + QString serviceDescription() const; + void setServiceDescription(const QString &description); + + QtServiceController::StartupType startupType() const; + void setStartupType(QtServiceController::StartupType startupType); + + ServiceFlags serviceFlags() const; + void setServiceFlags(ServiceFlags flags); + + int exec(); + + void logMessage(const QString &message, MessageType type = Success, + int id = 0, uint category = 0, const QByteArray &data = QByteArray()); + + static QtServiceBase *instance(); + +protected: + + virtual void start() = 0; + virtual void stop(); + virtual void pause(); + virtual void resume(); + virtual void processCommand(int code); + + virtual void createApplication(int &argc, char **argv) = 0; + + virtual int executeApplication() = 0; + +private: + + friend class QtServiceSysPrivate; + QtServiceBasePrivate *d_ptr; +}; + +template +class QtService : public QtServiceBase +{ +public: + QtService(int argc, char **argv, const QString &name) + : QtServiceBase(argc, argv, name), app(0) + { } + ~QtService() + { + } + +protected: + Application *application() const + { return app; } + + virtual void createApplication(int &argc, char **argv) + { + app = new Application(argc, argv); + QCoreApplication *a = app; + Q_UNUSED(a); + } + + virtual int executeApplication() + { return Application::exec(); } + +private: + Application *app; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QtServiceBase::ServiceFlags) + +#endif // QTSERVICE_H diff --git a/service/src/qtservice.pri b/service/src/qtservice.pri new file mode 100644 index 00000000..09452981 --- /dev/null +++ b/service/src/qtservice.pri @@ -0,0 +1,21 @@ +include(../common.pri) +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +!win32:QT += network +win32:LIBS += -luser32 + +qtservice-uselib:!qtservice-buildlib { + LIBS += -L$$QTSERVICE_LIBDIR -l$$QTSERVICE_LIBNAME +} else { + HEADERS += $$PWD/qtservice.h \ + $$PWD/qtservice_p.h + SOURCES += $$PWD/qtservice.cpp + win32:SOURCES += $$PWD/qtservice_win.cpp + unix:HEADERS += $$PWD/qtunixsocket.h $$PWD/qtunixserversocket.h + unix:SOURCES += $$PWD/qtservice_unix.cpp $$PWD/qtunixsocket.cpp $$PWD/qtunixserversocket.cpp +} + +win32 { + qtservice-buildlib:shared:DEFINES += QT_QTSERVICE_EXPORT + else:qtservice-uselib:DEFINES += QT_QTSERVICE_IMPORT +} diff --git a/service/src/qtservice_p.h b/service/src/qtservice_p.h new file mode 100644 index 00000000..a88992cf --- /dev/null +++ b/service/src/qtservice_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSERVICE_P_H +#define QTSERVICE_P_H + +#include +#include "qtservice.h" + +class QtServiceControllerPrivate +{ + Q_DECLARE_PUBLIC(QtServiceController) +public: + QString serviceName; + QtServiceController *q_ptr; +}; + +class QtServiceBasePrivate +{ + Q_DECLARE_PUBLIC(QtServiceBase) +public: + + QtServiceBasePrivate(const QString &name); + ~QtServiceBasePrivate(); + + QtServiceBase *q_ptr; + + QString serviceDescription; + QtServiceController::StartupType startupType; + QtServiceBase::ServiceFlags serviceFlags; + QStringList args; + + static class QtServiceBase *instance; + + QtServiceController controller; + + void startService(); + int run(bool asService, const QStringList &argList); + bool install(const QString &account, const QString &password); + + bool start(); + + QString filePath() const; + bool sysInit(); + void sysSetPath(); + void sysCleanup(); + class QtServiceSysPrivate *sysd; +}; + +#endif diff --git a/service/src/qtservice_unix.cpp b/service/src/qtservice_unix.cpp new file mode 100644 index 00000000..345acc6a --- /dev/null +++ b/service/src/qtservice_unix.cpp @@ -0,0 +1,482 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtservice.h" +#include "qtservice_p.h" +#include "qtunixsocket.h" +#include "qtunixserversocket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static QString encodeName(const QString &name, bool allowUpper = false) +{ + QString n = name.toLower(); + QString legal = QLatin1String("abcdefghijklmnopqrstuvwxyz1234567890"); + if (allowUpper) + legal += QLatin1String("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + int pos = 0; + while (pos < n.size()) { + if (legal.indexOf(n[pos]) == -1) + n.remove(pos, 1); + else + ++pos; + } + return n; +} + +static QString login() +{ + QString l; + uid_t uid = getuid(); + passwd *pw = getpwuid(uid); + if (pw) + l = QString(pw->pw_name); + return l; +} + +static QString socketPath(const QString &serviceName) +{ + QString sn = encodeName(serviceName); + return QString(QLatin1String("/var/tmp/") + sn + QLatin1String(".") + login()); +} + +static bool sendCmd(const QString &serviceName, const QString &cmd) +{ + bool retValue = false; + QtUnixSocket sock; + if (sock.connectTo(socketPath(serviceName))) { + sock.write(QString(cmd+"\r\n").toLatin1().constData()); + sock.flush(); + sock.waitForReadyRead(-1); + QString reply = sock.readAll(); + if (reply == QLatin1String("true")) + retValue = true; + sock.close(); + } + return retValue; +} + +static QString absPath(const QString &path) +{ + QString ret; + if (path[0] != QChar('/')) { // Not an absolute path + int slashpos; + if ((slashpos = path.lastIndexOf('/')) != -1) { // Relative path + QDir dir = QDir::current(); + dir.cd(path.left(slashpos)); + ret = dir.absolutePath(); + } else { // Need to search $PATH + char *envPath = ::getenv("PATH"); + if (envPath) { + QStringList envPaths = QString::fromLocal8Bit(envPath).split(':'); + for (int i = 0; i < envPaths.size(); ++i) { + if (QFile::exists(envPaths.at(i) + QLatin1String("/") + QString(path))) { + QDir dir(envPaths.at(i)); + ret = dir.absolutePath(); + break; + } + } + } + } + } else { + QFileInfo fi(path); + ret = fi.absolutePath(); + } + return ret; +} + +QString QtServiceBasePrivate::filePath() const +{ + QString ret; + if (args.isEmpty()) + return ret; + QFileInfo fi(args[0]); + QDir dir(absPath(args[0])); + return dir.absoluteFilePath(fi.fileName()); +} + + +QString QtServiceController::serviceDescription() const +{ + QSettings settings(QSettings::SystemScope, "QtSoftware"); + settings.beginGroup("services"); + settings.beginGroup(serviceName()); + + QString desc = settings.value("description").toString(); + + settings.endGroup(); + settings.endGroup(); + + return desc; +} + +QtServiceController::StartupType QtServiceController::startupType() const +{ + QSettings settings(QSettings::SystemScope, "QtSoftware"); + settings.beginGroup("services"); + settings.beginGroup(serviceName()); + + StartupType startupType = (StartupType)settings.value("startupType").toInt(); + + settings.endGroup(); + settings.endGroup(); + + return startupType; +} + +QString QtServiceController::serviceFilePath() const +{ + QSettings settings(QSettings::SystemScope, "QtSoftware"); + settings.beginGroup("services"); + settings.beginGroup(serviceName()); + + QString path = settings.value("path").toString(); + + settings.endGroup(); + settings.endGroup(); + + return path; +} + +bool QtServiceController::uninstall() +{ + QSettings settings(QSettings::SystemScope, "QtSoftware"); + settings.beginGroup("services"); + + settings.remove(serviceName()); + + settings.endGroup(); + settings.sync(); + + QSettings::Status ret = settings.status(); + if (ret == QSettings::AccessError) { + fprintf(stderr, "Cannot uninstall \"%s\". Cannot write to: %s. Check permissions.\n", + serviceName().toLatin1().constData(), + settings.fileName().toLatin1().constData()); + } + return (ret == QSettings::NoError); +} + + +bool QtServiceController::start(const QStringList &arguments) +{ + if (!isInstalled()) + return false; + if (isRunning()) + return false; + return QProcess::startDetached(serviceFilePath(), arguments); +} + +bool QtServiceController::stop() +{ + return sendCmd(serviceName(), QLatin1String("terminate")); +} + +bool QtServiceController::pause() +{ + return sendCmd(serviceName(), QLatin1String("pause")); +} + +bool QtServiceController::resume() +{ + return sendCmd(serviceName(), QLatin1String("resume")); +} + +bool QtServiceController::sendCommand(int code) +{ + return sendCmd(serviceName(), QString(QLatin1String("num:") + QString::number(code))); +} + +bool QtServiceController::isInstalled() const +{ + QSettings settings(QSettings::SystemScope, "QtSoftware"); + settings.beginGroup("services"); + + QStringList list = settings.childGroups(); + + settings.endGroup(); + + QStringListIterator it(list); + while (it.hasNext()) { + if (it.next() == serviceName()) + return true; + } + + return false; +} + +bool QtServiceController::isRunning() const +{ + QtUnixSocket sock; + if (sock.connectTo(socketPath(serviceName()))) + return true; + return false; +} + + + + +/////////////////////////////////// + +class QtServiceSysPrivate : public QtUnixServerSocket +{ + Q_OBJECT +public: + QtServiceSysPrivate(); + ~QtServiceSysPrivate(); + + char *ident; + + QtServiceBase::ServiceFlags serviceFlags; + +protected: +#if QT_VERSION >= 0x050000 + void incomingConnection(qintptr socketDescriptor); +#else + void incomingConnection(int socketDescriptor); +#endif + +private slots: + void slotReady(); + void slotClosed(); + +private: + QString getCommand(const QTcpSocket *socket); + QMap cache; +}; + +QtServiceSysPrivate::QtServiceSysPrivate() + : QtUnixServerSocket(), ident(0), serviceFlags(0) +{ +} + +QtServiceSysPrivate::~QtServiceSysPrivate() +{ + if (ident) + delete[] ident; +} + +#if QT_VERSION >= 0x050000 +void QtServiceSysPrivate::incomingConnection(qintptr socketDescriptor) +#else +void QtServiceSysPrivate::incomingConnection(int socketDescriptor) +#endif +{ + QTcpSocket *s = new QTcpSocket(this); + s->setSocketDescriptor(socketDescriptor); + connect(s, SIGNAL(readyRead()), this, SLOT(slotReady())); + connect(s, SIGNAL(disconnected()), this, SLOT(slotClosed())); +} + +void QtServiceSysPrivate::slotReady() +{ + QTcpSocket *s = (QTcpSocket *)sender(); + cache[s] += QString(s->readAll()); + QString cmd = getCommand(s); + while (!cmd.isEmpty()) { + bool retValue = false; + if (cmd == QLatin1String("terminate")) { + if (!(serviceFlags & QtServiceBase::CannotBeStopped)) { + QtServiceBase::instance()->stop(); + QCoreApplication::instance()->quit(); + retValue = true; + } + } else if (cmd == QLatin1String("pause")) { + if (serviceFlags & QtServiceBase::CanBeSuspended) { + QtServiceBase::instance()->pause(); + retValue = true; + } + } else if (cmd == QLatin1String("resume")) { + if (serviceFlags & QtServiceBase::CanBeSuspended) { + QtServiceBase::instance()->resume(); + retValue = true; + } + } else if (cmd == QLatin1String("alive")) { + retValue = true; + } else if (cmd.length() > 4 && cmd.left(4) == QLatin1String("num:")) { + cmd = cmd.mid(4); + QtServiceBase::instance()->processCommand(cmd.toInt()); + retValue = true; + } + QString retString; + if (retValue) + retString = QLatin1String("true"); + else + retString = QLatin1String("false"); + s->write(retString.toLatin1().constData()); + s->flush(); + cmd = getCommand(s); + } +} + +void QtServiceSysPrivate::slotClosed() +{ + QTcpSocket *s = (QTcpSocket *)sender(); + s->deleteLater(); +} + +QString QtServiceSysPrivate::getCommand(const QTcpSocket *socket) +{ + int pos = cache[socket].indexOf("\r\n"); + if (pos >= 0) { + QString ret = cache[socket].left(pos); + cache[socket].remove(0, pos+2); + return ret; + } + return ""; +} + +#include "qtservice_unix.moc" + +bool QtServiceBasePrivate::sysInit() +{ + sysd = new QtServiceSysPrivate; + sysd->serviceFlags = serviceFlags; + // Restrict permissions on files that are created by the service + ::umask(027); + + return true; +} + +void QtServiceBasePrivate::sysSetPath() +{ + if (sysd) + sysd->setPath(socketPath(controller.serviceName())); +} + +void QtServiceBasePrivate::sysCleanup() +{ + if (sysd) { + sysd->close(); + delete sysd; + sysd = 0; + } +} + +bool QtServiceBasePrivate::start() +{ + if (sendCmd(controller.serviceName(), "alive")) { + // Already running + return false; + } + // Could just call controller.start() here, but that would fail if + // we're not installed. We do not want to strictly require installation. + ::setenv("QTSERVICE_RUN", "1", 1); // Tell the detached process it's it + return QProcess::startDetached(filePath(), args.mid(1), "/"); +} + +bool QtServiceBasePrivate::install(const QString &account, const QString &password) +{ + Q_UNUSED(account) + Q_UNUSED(password) + QSettings settings(QSettings::SystemScope, "QtSoftware"); + + settings.beginGroup("services"); + settings.beginGroup(controller.serviceName()); + + settings.setValue("path", filePath()); + settings.setValue("description", serviceDescription); + settings.setValue("automaticStartup", startupType); + + settings.endGroup(); + settings.endGroup(); + settings.sync(); + + QSettings::Status ret = settings.status(); + if (ret == QSettings::AccessError) { + fprintf(stderr, "Cannot install \"%s\". Cannot write to: %s. Check permissions.\n", + controller.serviceName().toLatin1().constData(), + settings.fileName().toLatin1().constData()); + } + return (ret == QSettings::NoError); +} + +void QtServiceBase::logMessage(const QString &message, QtServiceBase::MessageType type, + int, uint, const QByteArray &) +{ + if (!d_ptr->sysd) + return; + int st; + switch(type) { + case QtServiceBase::Error: + st = LOG_ERR; + break; + case QtServiceBase::Warning: + st = LOG_WARNING; + break; + default: + st = LOG_INFO; + } + if (!d_ptr->sysd->ident) { + QString tmp = encodeName(serviceName(), true); + int len = tmp.toLocal8Bit().size(); + d_ptr->sysd->ident = new char[len+1]; + d_ptr->sysd->ident[len] = '\0'; + ::memcpy(d_ptr->sysd->ident, tmp.toLocal8Bit().constData(), len); + } + openlog(d_ptr->sysd->ident, LOG_PID, LOG_DAEMON); + foreach(QString line, message.split('\n')) + syslog(st, "%s", line.toLocal8Bit().constData()); + closelog(); +} + +void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags) +{ + if (d_ptr->serviceFlags == flags) + return; + d_ptr->serviceFlags = flags; + if (d_ptr->sysd) + d_ptr->sysd->serviceFlags = flags; +} + diff --git a/service/src/qtservice_win.cpp b/service/src/qtservice_win.cpp new file mode 100644 index 00000000..e5b7ecc5 --- /dev/null +++ b/service/src/qtservice_win.cpp @@ -0,0 +1,952 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtservice.h" +#include "qtservice_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if QT_VERSION >= 0x050000 +# include +#endif +#include +#if defined(QTSERVICE_DEBUG) +#include +#endif + +typedef SERVICE_STATUS_HANDLE(WINAPI*PRegisterServiceCtrlHandler)(const wchar_t*,LPHANDLER_FUNCTION); +static PRegisterServiceCtrlHandler pRegisterServiceCtrlHandler = 0; +typedef BOOL(WINAPI*PSetServiceStatus)(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS); +static PSetServiceStatus pSetServiceStatus = 0; +typedef BOOL(WINAPI*PChangeServiceConfig2)(SC_HANDLE,DWORD,LPVOID); +static PChangeServiceConfig2 pChangeServiceConfig2 = 0; +typedef BOOL(WINAPI*PCloseServiceHandle)(SC_HANDLE); +static PCloseServiceHandle pCloseServiceHandle = 0; +typedef SC_HANDLE(WINAPI*PCreateService)(SC_HANDLE,LPCTSTR,LPCTSTR,DWORD,DWORD,DWORD,DWORD,LPCTSTR,LPCTSTR,LPDWORD,LPCTSTR,LPCTSTR,LPCTSTR); +static PCreateService pCreateService = 0; +typedef SC_HANDLE(WINAPI*POpenSCManager)(LPCTSTR,LPCTSTR,DWORD); +static POpenSCManager pOpenSCManager = 0; +typedef BOOL(WINAPI*PDeleteService)(SC_HANDLE); +static PDeleteService pDeleteService = 0; +typedef SC_HANDLE(WINAPI*POpenService)(SC_HANDLE,LPCTSTR,DWORD); +static POpenService pOpenService = 0; +typedef BOOL(WINAPI*PQueryServiceStatus)(SC_HANDLE,LPSERVICE_STATUS); +static PQueryServiceStatus pQueryServiceStatus = 0; +typedef BOOL(WINAPI*PStartServiceCtrlDispatcher)(CONST SERVICE_TABLE_ENTRY*); +static PStartServiceCtrlDispatcher pStartServiceCtrlDispatcher = 0; +typedef BOOL(WINAPI*PStartService)(SC_HANDLE,DWORD,const wchar_t**); +static PStartService pStartService = 0; +typedef BOOL(WINAPI*PControlService)(SC_HANDLE,DWORD,LPSERVICE_STATUS); +static PControlService pControlService = 0; +typedef HANDLE(WINAPI*PDeregisterEventSource)(HANDLE); +static PDeregisterEventSource pDeregisterEventSource = 0; +typedef BOOL(WINAPI*PReportEvent)(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCTSTR*,LPVOID); +static PReportEvent pReportEvent = 0; +typedef HANDLE(WINAPI*PRegisterEventSource)(LPCTSTR,LPCTSTR); +static PRegisterEventSource pRegisterEventSource = 0; +typedef DWORD(WINAPI*PRegisterServiceProcess)(DWORD,DWORD); +static PRegisterServiceProcess pRegisterServiceProcess = 0; +typedef BOOL(WINAPI*PQueryServiceConfig)(SC_HANDLE,LPQUERY_SERVICE_CONFIG,DWORD,LPDWORD); +static PQueryServiceConfig pQueryServiceConfig = 0; +typedef BOOL(WINAPI*PQueryServiceConfig2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); +static PQueryServiceConfig2 pQueryServiceConfig2 = 0; + + +#define RESOLVE(name) p##name = (P##name)lib.resolve(#name); +#define RESOLVEA(name) p##name = (P##name)lib.resolve(#name"A"); +#define RESOLVEW(name) p##name = (P##name)lib.resolve(#name"W"); + +static bool winServiceInit() +{ + if (!pOpenSCManager) { + QLibrary lib("advapi32"); + + // only resolve unicode versions + RESOLVEW(RegisterServiceCtrlHandler); + RESOLVE(SetServiceStatus); + RESOLVEW(ChangeServiceConfig2); + RESOLVE(CloseServiceHandle); + RESOLVEW(CreateService); + RESOLVEW(OpenSCManager); + RESOLVE(DeleteService); + RESOLVEW(OpenService); + RESOLVE(QueryServiceStatus); + RESOLVEW(StartServiceCtrlDispatcher); + RESOLVEW(StartService); // need only Ansi version + RESOLVE(ControlService); + RESOLVE(DeregisterEventSource); + RESOLVEW(ReportEvent); + RESOLVEW(RegisterEventSource); + RESOLVEW(QueryServiceConfig); + RESOLVEW(QueryServiceConfig2); + } + return pOpenSCManager != 0; +} + +bool QtServiceController::isInstalled() const +{ + Q_D(const QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t*)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + + if (hService) { + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::isRunning() const +{ + Q_D(const QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_STATUS); + if (hService) { + SERVICE_STATUS info; + int res = pQueryServiceStatus(hService, &info); + if (res) + result = info.dwCurrentState != SERVICE_STOPPED; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + + +QString QtServiceController::serviceFilePath() const +{ + Q_D(const QtServiceController); + QString result; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD sizeNeeded = 0; + char data[8 * 1024]; + if (pQueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)data, 8 * 1024, &sizeNeeded)) { + LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)data; + result = QString::fromUtf16((const ushort*)config->lpBinaryPathName); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +QString QtServiceController::serviceDescription() const +{ + Q_D(const QtServiceController); + QString result; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD dwBytesNeeded; + char data[8 * 1024]; + if (pQueryServiceConfig2( + hService, + SERVICE_CONFIG_DESCRIPTION, + (unsigned char *)data, + 8096, + &dwBytesNeeded)) { + LPSERVICE_DESCRIPTION desc = (LPSERVICE_DESCRIPTION)data; + if (desc->lpDescription) + result = QString::fromUtf16((const ushort*)desc->lpDescription); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +QtServiceController::StartupType QtServiceController::startupType() const +{ + Q_D(const QtServiceController); + StartupType result = ManualStartup; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD sizeNeeded = 0; + char data[8 * 1024]; + if (pQueryServiceConfig(hService, (QUERY_SERVICE_CONFIG *)data, 8 * 1024, &sizeNeeded)) { + QUERY_SERVICE_CONFIG *config = (QUERY_SERVICE_CONFIG *)data; + result = config->dwStartType == SERVICE_DEMAND_START ? ManualStartup : AutoStartup; + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::uninstall() +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), DELETE); + if (hService) { + if (pDeleteService(hService)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::start(const QStringList &args) +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_START); + if (hService) { + QVector argv(args.size()); + for (int i = 0; i < args.size(); ++i) + argv[i] = (const wchar_t*)args.at(i).utf16(); + + if (pStartService(hService, args.size(), argv.data())) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::stop() +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_STOP|SERVICE_QUERY_STATUS); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_STOP, &status)) { + bool stopped = status.dwCurrentState == SERVICE_STOPPED; + int i = 0; + while(!stopped && i < 10) { + Sleep(200); + if (!pQueryServiceStatus(hService, &status)) + break; + stopped = status.dwCurrentState == SERVICE_STOPPED; + ++i; + } + result = stopped; + } else { + qErrnoWarning(GetLastError(), "stopping"); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::pause() +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_PAUSE_CONTINUE); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_PAUSE, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::resume() +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_PAUSE_CONTINUE); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_CONTINUE, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +bool QtServiceController::sendCommand(int code) +{ + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + if (code < 0 || code > 127 || !isRunning()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_USER_DEFINED_CONTROL); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, 128 + code, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +#if defined(QTSERVICE_DEBUG) +# if QT_VERSION >= 0x050000 +extern void qtServiceLogDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg); +# else +extern void qtServiceLogDebug(QtMsgType type, const char* msg); +# endif +#endif + +void QtServiceBase::logMessage(const QString &message, MessageType type, + int id, uint category, const QByteArray &data) +{ +#if defined(QTSERVICE_DEBUG) + QByteArray dbgMsg("[LOGGED "); + switch (type) { + case Error: dbgMsg += "Error] " ; break; + case Warning: dbgMsg += "Warning] "; break; + case Success: dbgMsg += "Success] "; break; + case Information: //fall through + default: dbgMsg += "Information] "; break; + } +# if QT_VERSION >= 0x050000 + qtServiceLogDebug((QtMsgType)-1, QMessageLogContext(), QLatin1String(dbgMsg) + message); +# else + qtServiceLogDebug((QtMsgType)-1, (dbgMsg + message.toAscii()).constData()); +# endif +#endif + + Q_D(QtServiceBase); + if (!winServiceInit()) + return; + WORD wType; + switch (type) { + case Error: wType = EVENTLOG_ERROR_TYPE; break; + case Warning: wType = EVENTLOG_WARNING_TYPE; break; + case Information: wType = EVENTLOG_INFORMATION_TYPE; break; + default: wType = EVENTLOG_SUCCESS; break; + } + HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16()); + if (h) { + const wchar_t *msg = (wchar_t*)message.utf16(); + const char *bindata = data.size() ? data.constData() : 0; + pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg, + const_cast(bindata)); + pDeregisterEventSource(h); + } +} + +class QtServiceControllerHandler : public QObject +{ + Q_OBJECT +public: + QtServiceControllerHandler(QtServiceSysPrivate *sys); + +protected: + void customEvent(QEvent *e); + +private: + QtServiceSysPrivate *d_sys; +}; + +class QtServiceSysPrivate +{ +public: + enum { + QTSERVICE_STARTUP = 256 + }; + QtServiceSysPrivate(); + + void setStatus( DWORD dwState ); + void setServiceFlags(QtServiceBase::ServiceFlags flags); + DWORD serviceFlags(QtServiceBase::ServiceFlags flags) const; + inline bool available() const; + static void WINAPI serviceMain( DWORD dwArgc, wchar_t** lpszArgv ); + static void WINAPI handler( DWORD dwOpcode ); + + SERVICE_STATUS status; + SERVICE_STATUS_HANDLE serviceStatus; + QStringList serviceArgs; + + static QtServiceSysPrivate *instance; +#if QT_VERSION < 0x050000 + static QCoreApplication::EventFilter nextFilter; +#endif + + QWaitCondition condition; + QMutex mutex; + QSemaphore startSemaphore; + QSemaphore startSemaphore2; + + QtServiceControllerHandler *controllerHandler; + + void handleCustomEvent(QEvent *e); +}; + +QtServiceControllerHandler::QtServiceControllerHandler(QtServiceSysPrivate *sys) + : QObject(), d_sys(sys) +{ + +} + +void QtServiceControllerHandler::customEvent(QEvent *e) +{ + d_sys->handleCustomEvent(e); +} + + +QtServiceSysPrivate *QtServiceSysPrivate::instance = 0; +#if QT_VERSION < 0x050000 +QCoreApplication::EventFilter QtServiceSysPrivate::nextFilter = 0; +#endif + +QtServiceSysPrivate::QtServiceSysPrivate() +{ + instance = this; +} + +inline bool QtServiceSysPrivate::available() const +{ + return 0 != pOpenSCManager; +} + +void WINAPI QtServiceSysPrivate::serviceMain(DWORD dwArgc, wchar_t** lpszArgv) +{ + if (!instance || !QtServiceBase::instance()) + return; + + // Windows spins off a random thread to call this function on + // startup, so here we just signal to the QApplication event loop + // in the main thread to go ahead with start()'ing the service. + + for (DWORD i = 0; i < dwArgc; i++) + instance->serviceArgs.append(QString::fromUtf16((unsigned short*)lpszArgv[i])); + + instance->startSemaphore.release(); // let the qapp creation start + instance->startSemaphore2.acquire(); // wait until its done + // Register the control request handler + instance->serviceStatus = pRegisterServiceCtrlHandler((TCHAR*)QtServiceBase::instance()->serviceName().utf16(), handler); + + if (!instance->serviceStatus) // cannot happen - something is utterly wrong + return; + + handler(QTSERVICE_STARTUP); // Signal startup to the application - + // causes QtServiceBase::start() to be called in the main thread + + // The MSDN doc says that this thread should just exit - the service is + // running in the main thread (here, via callbacks in the handler thread). +} + + +// The handler() is called from the thread that called +// StartServiceCtrlDispatcher, i.e. our HandlerThread, and +// not from the main thread that runs the event loop, so we +// have to post an event to ourselves, and use a QWaitCondition +// and a QMutex to synchronize. +void QtServiceSysPrivate::handleCustomEvent(QEvent *e) +{ + int code = e->type() - QEvent::User; + + switch(code) { + case QTSERVICE_STARTUP: // Startup + QtServiceBase::instance()->start(); + break; + case SERVICE_CONTROL_STOP: + QtServiceBase::instance()->stop(); + QCoreApplication::instance()->quit(); + break; + case SERVICE_CONTROL_PAUSE: + QtServiceBase::instance()->pause(); + break; + case SERVICE_CONTROL_CONTINUE: + QtServiceBase::instance()->resume(); + break; + default: + if (code >= 128 && code <= 255) + QtServiceBase::instance()->processCommand(code - 128); + break; + } + + mutex.lock(); + condition.wakeAll(); + mutex.unlock(); +} + +void WINAPI QtServiceSysPrivate::handler( DWORD code ) +{ + if (!instance) + return; + + instance->mutex.lock(); + switch (code) { + case QTSERVICE_STARTUP: // QtService startup (called from WinMain when started) + instance->setStatus(SERVICE_START_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_RUNNING); + break; + case SERVICE_CONTROL_STOP: // 1 + instance->setStatus(SERVICE_STOP_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + // status will be reported as stopped by start() when qapp::exec returns + break; + + case SERVICE_CONTROL_PAUSE: // 2 + instance->setStatus(SERVICE_PAUSE_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_PAUSED); + break; + + case SERVICE_CONTROL_CONTINUE: // 3 + instance->setStatus(SERVICE_CONTINUE_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_RUNNING); + break; + + case SERVICE_CONTROL_INTERROGATE: // 4 + break; + + case SERVICE_CONTROL_SHUTDOWN: // 5 + // Don't waste time with reporting stop pending, just do it + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + SERVICE_CONTROL_STOP))); + instance->condition.wait(&instance->mutex); + // status will be reported as stopped by start() when qapp::exec returns + break; + + default: + if ( code >= 128 && code <= 255 ) { + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + } + break; + } + + instance->mutex.unlock(); + + // Report current status + if (instance->available() && instance->status.dwCurrentState != SERVICE_STOPPED) + pSetServiceStatus(instance->serviceStatus, &instance->status); +} + +void QtServiceSysPrivate::setStatus(DWORD state) +{ + if (!available()) + return; + status.dwCurrentState = state; + pSetServiceStatus(serviceStatus, &status); +} + +void QtServiceSysPrivate::setServiceFlags(QtServiceBase::ServiceFlags flags) +{ + if (!available()) + return; + status.dwControlsAccepted = serviceFlags(flags); + pSetServiceStatus(serviceStatus, &status); +} + +DWORD QtServiceSysPrivate::serviceFlags(QtServiceBase::ServiceFlags flags) const +{ + DWORD control = 0; + if (flags & QtServiceBase::CanBeSuspended) + control |= SERVICE_ACCEPT_PAUSE_CONTINUE; + if (!(flags & QtServiceBase::CannotBeStopped)) + control |= SERVICE_ACCEPT_STOP; + if (flags & QtServiceBase::NeedsStopOnShutdown) + control |= SERVICE_ACCEPT_SHUTDOWN; + + return control; +} + +#include "qtservice_win.moc" + + +class HandlerThread : public QThread +{ +public: + HandlerThread() + : success(true), console(false), QThread() + {} + + bool calledOk() { return success; } + bool runningAsConsole() { return console; } + +protected: + bool success, console; + void run() + { + SERVICE_TABLE_ENTRYW st [2]; + st[0].lpServiceName = (wchar_t*)QtServiceBase::instance()->serviceName().utf16(); + st[0].lpServiceProc = QtServiceSysPrivate::serviceMain; + st[1].lpServiceName = 0; + st[1].lpServiceProc = 0; + + success = (pStartServiceCtrlDispatcher(st) != 0); // should block + + if (!success) { + if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { + // Means we're started from console, not from service mgr + // start() will ask the mgr to start another instance of us as a service instead + console = true; + } + else { + QtServiceBase::instance()->logMessage(QString("The Service failed to start [%1]").arg(qt_error_string(GetLastError())), QtServiceBase::Error); + } + QtServiceSysPrivate::instance->startSemaphore.release(); // let start() continue, since serviceMain won't be doing it + } + } +}; + +/* + Ignore WM_ENDSESSION system events, since they make the Qt kernel quit +*/ + +#if QT_VERSION >= 0x050000 + +class QtServiceAppEventFilter : public QAbstractNativeEventFilter +{ +public: + QtServiceAppEventFilter() {} + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); +}; + +bool QtServiceAppEventFilter::nativeEventFilter(const QByteArray &, void *message, long *result) +{ + MSG *winMessage = (MSG*)message; + if (winMessage->message == WM_ENDSESSION && (winMessage->lParam & ENDSESSION_LOGOFF)) { + *result = TRUE; + return true; + } + return false; +} + +Q_GLOBAL_STATIC(QtServiceAppEventFilter, qtServiceAppEventFilter) + +#else + +bool myEventFilter(void* message, long* result) +{ + MSG* msg = reinterpret_cast(message); + if (!msg || (msg->message != WM_ENDSESSION) || !(msg->lParam & ENDSESSION_LOGOFF)) + return QtServiceSysPrivate::nextFilter ? QtServiceSysPrivate::nextFilter(message, result) : false; + + if (QtServiceSysPrivate::nextFilter) + QtServiceSysPrivate::nextFilter(message, result); + if (result) + *result = TRUE; + return true; +} + +#endif + +/* There are three ways we can be started: + + - By a service controller (e.g. the Services control panel), with + no (service-specific) arguments. ServiceBase::exec() will then call + start() below, and the service will start. + + - From the console, but with no (service-specific) arguments. This + means we should ask a controller to start the service (i.e. another + instance of this executable), and then just terminate. We discover + this case (as different from the above) by the fact that + StartServiceCtrlDispatcher will return an error, instead of blocking. + + - From the console, with -e(xec) argument. ServiceBase::exec() will + then call ServiceBasePrivate::exec(), which calls + ServiceBasePrivate::run(), which runs the application as a normal + program. +*/ + +bool QtServiceBasePrivate::start() +{ + sysInit(); + if (!winServiceInit()) + return false; + + // Since StartServiceCtrlDispatcher() blocks waiting for service + // control events, we need to call it in another thread, so that + // the main thread can run the QApplication event loop. + HandlerThread* ht = new HandlerThread(); + ht->start(); + + QtServiceSysPrivate* sys = QtServiceSysPrivate::instance; + + // Wait until service args have been received by serviceMain. + // If Windows doesn't call serviceMain (or + // StartServiceControlDispatcher doesn't return an error) within + // a timeout of 20 secs, something is very wrong; give up + if (!sys->startSemaphore.tryAcquire(1, 20000)) + return false; + + if (!ht->calledOk()) { + if (ht->runningAsConsole()) + return controller.start(args.mid(1)); + else + return false; + } + + int argc = sys->serviceArgs.size(); + QVector argv(argc); + QList argvData; + for (int i = 0; i < argc; ++i) + argvData.append(sys->serviceArgs.at(i).toLocal8Bit()); + for (int i = 0; i < argc; ++i) + argv[i] = argvData[i].data(); + + q_ptr->createApplication(argc, argv.data()); + QCoreApplication *app = QCoreApplication::instance(); + if (!app) + return false; + +#if QT_VERSION >= 0x050000 + QAbstractEventDispatcher::instance()->installNativeEventFilter(qtServiceAppEventFilter()); +#else + QtServiceSysPrivate::nextFilter = app->setEventFilter(myEventFilter); +#endif + + sys->controllerHandler = new QtServiceControllerHandler(sys); + + sys->startSemaphore2.release(); // let serviceMain continue (and end) + + sys->status.dwWin32ExitCode = q_ptr->executeApplication(); + sys->setStatus(SERVICE_STOPPED); + + if (ht->isRunning()) + ht->wait(1000); // let the handler thread finish + delete sys->controllerHandler; + sys->controllerHandler = 0; + if (ht->isFinished()) + delete ht; + delete app; + sysCleanup(); + return true; +} + +bool QtServiceBasePrivate::install(const QString &account, const QString &password) +{ + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if (hSCM) { + QString acc = account; + DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START; + DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS; + wchar_t *act = 0; + wchar_t *pwd = 0; + if (!acc.isEmpty()) { + // The act string must contain a string of the format "Domain\UserName", + // so if only a username was specified without a domain, default to the local machine domain. + if (!acc.contains(QChar('\\'))) { + acc.prepend(QLatin1String(".\\")); + } + if (!acc.endsWith(QLatin1String("\\LocalSystem"))) + act = (wchar_t*)acc.utf16(); + } + if (!password.isEmpty() && act) { + pwd = (wchar_t*)password.utf16(); + } + + // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem). + if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS; + + // Create the service + SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(), + (wchar_t *)controller.serviceName().utf16(), + SERVICE_ALL_ACCESS, + dwServiceType, // QObject::inherits ( const char * className ) for no inter active ???? + dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(), + 0, 0, 0, + act, pwd); + if (hService) { + result = true; + if (!serviceDescription.isEmpty()) { + SERVICE_DESCRIPTION sdesc; + sdesc.lpDescription = (wchar_t *)serviceDescription.utf16(); + pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; +} + +QString QtServiceBasePrivate::filePath() const +{ + wchar_t path[_MAX_PATH]; + ::GetModuleFileNameW( 0, path, sizeof(path) ); + return QString::fromUtf16((unsigned short*)path); +} + +bool QtServiceBasePrivate::sysInit() +{ + sysd = new QtServiceSysPrivate(); + + sysd->serviceStatus = 0; + sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; + sysd->status.dwCurrentState = SERVICE_STOPPED; + sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags); + sysd->status.dwWin32ExitCode = NO_ERROR; + sysd->status.dwServiceSpecificExitCode = 0; + sysd->status.dwCheckPoint = 0; + sysd->status.dwWaitHint = 0; + + return true; +} + +void QtServiceBasePrivate::sysSetPath() +{ + +} + +void QtServiceBasePrivate::sysCleanup() +{ + if (sysd) { + delete sysd; + sysd = 0; + } +} + +void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags) +{ + if (d_ptr->serviceFlags == flags) + return; + d_ptr->serviceFlags = flags; + if (d_ptr->sysd) + d_ptr->sysd->setServiceFlags(flags); +} + + diff --git a/service/src/qtunixserversocket.cpp b/service/src/qtunixserversocket.cpp new file mode 100644 index 00000000..0ad9134c --- /dev/null +++ b/service/src/qtunixserversocket.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtunixserversocket.h" +#include +#include +#include +#include +#include + +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \ + +strlen ((ptr)->sun_path)) +#endif + +QtUnixServerSocket::QtUnixServerSocket(const QString &path, QObject *parent) + : QTcpServer(parent) +{ + setPath(path); +} + +QtUnixServerSocket::QtUnixServerSocket(QObject *parent) + : QTcpServer(parent) +{ +} + +void QtUnixServerSocket::setPath(const QString &path) +{ + path_.clear(); + + int sock = ::socket(PF_UNIX, SOCK_STREAM, 0); + if (sock != -1) { + struct sockaddr_un addr; + ::memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + ::unlink(path.toLatin1().constData()); // ### This might need to be changed + unsigned int pathlen = strlen(path.toLatin1().constData()); + if (pathlen > sizeof(addr.sun_path)) pathlen = sizeof(addr.sun_path); + ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen); + if ((::bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)) != -1) && + (::listen(sock, 5) != -1)) { + setSocketDescriptor(sock); + path_ = path; + } + } +} + +void QtUnixServerSocket::close() +{ + QTcpServer::close(); + if (!path_.isEmpty()) { + ::unlink(path_.toLatin1().constData()); + path_.clear(); + } +} diff --git a/service/src/qtunixserversocket.h b/service/src/qtunixserversocket.h new file mode 100644 index 00000000..1fc8b702 --- /dev/null +++ b/service/src/qtunixserversocket.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTUNIXSERVERSOCKET_H +#define QTUNIXSERVERSOCKET_H + +#include + +class QtUnixServerSocket : public QTcpServer +{ + Q_OBJECT +public: + QtUnixServerSocket(const QString &path, QObject *parent = 0); + QtUnixServerSocket(QObject *parent = 0); + + void setPath(const QString &path); + void close(); + +private: + QString path_; +}; + + +#endif diff --git a/service/src/qtunixsocket.cpp b/service/src/qtunixsocket.cpp new file mode 100644 index 00000000..f6d4c970 --- /dev/null +++ b/service/src/qtunixsocket.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtunixsocket.h" +#include +#include +#include +#include +#include + +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \ + +strlen ((ptr)->sun_path)) +#endif + +QtUnixSocket::QtUnixSocket(QObject *parent) + : QTcpSocket(parent) +{ +} + +bool QtUnixSocket::connectTo(const QString &path) +{ + bool ret = false; + int sock = ::socket(PF_UNIX, SOCK_STREAM, 0); + if (sock != -1) { + struct sockaddr_un addr; + ::memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + size_t pathlen = strlen(path.toLatin1().constData()); + pathlen = qMin(pathlen, sizeof(addr.sun_path)); + ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen); + int err = ::connect(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); + if (err != -1) { + setSocketDescriptor(sock); + ret = true; + } else { + ::close(sock); + } + } + return ret; +} diff --git a/service/src/qtunixsocket.h b/service/src/qtunixsocket.h new file mode 100644 index 00000000..1d34fba4 --- /dev/null +++ b/service/src/qtunixsocket.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** 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 +** OWNER 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTUNIXSOCKET_H +#define QTUNIXSOCKET_H + +#include + +class QtUnixSocket : public QTcpSocket +{ + Q_OBJECT +public: + QtUnixSocket(QObject *parent = 0); + + bool connectTo(const QString &path); +}; + +#endif