From a428464573b0d99e07e2752bbd89b650889af2e8 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sun, 21 Nov 2010 16:19:27 +0100 Subject: [PATCH] Add Salsa20 cipher. Restructure SymmetricCipher implementation to allow multiple backends. --- COPYING | 4 + src/CMakeLists.txt | 8 + src/crypto/Crypto.cpp | 1 + src/crypto/SymmetricCipher.cpp | 117 ++-------- src/crypto/SymmetricCipher.h | 12 +- src/crypto/SymmetricCipherBackend.h | 41 ++++ src/crypto/SymmetricCipherGcrypt.cpp | 137 ++++++++++++ src/crypto/SymmetricCipherGcrypt.h | 52 +++++ src/crypto/SymmetricCipherSalsa20.cpp | 88 ++++++++ src/crypto/SymmetricCipherSalsa20.h | 47 ++++ src/crypto/salsa20/ecrypt-config.h | 297 ++++++++++++++++++++++++ src/crypto/salsa20/ecrypt-machine.h | 49 ++++ src/crypto/salsa20/ecrypt-portable.h | 310 ++++++++++++++++++++++++++ src/crypto/salsa20/ecrypt-sync.h | 287 ++++++++++++++++++++++++ src/crypto/salsa20/salsa20.c | 133 +++++++++++ tests/TestSymmetricCipher.cpp | 54 +++++ 16 files changed, 1533 insertions(+), 104 deletions(-) create mode 100644 src/crypto/SymmetricCipherBackend.h create mode 100644 src/crypto/SymmetricCipherGcrypt.cpp create mode 100644 src/crypto/SymmetricCipherGcrypt.h create mode 100644 src/crypto/SymmetricCipherSalsa20.cpp create mode 100644 src/crypto/SymmetricCipherSalsa20.h create mode 100644 src/crypto/salsa20/ecrypt-config.h create mode 100644 src/crypto/salsa20/ecrypt-machine.h create mode 100644 src/crypto/salsa20/ecrypt-portable.h create mode 100644 src/crypto/salsa20/ecrypt-sync.h create mode 100644 src/crypto/salsa20/salsa20.c diff --git a/COPYING b/COPYING index 193f5d84c..a86ddcb38 100644 --- a/COPYING +++ b/COPYING @@ -30,6 +30,10 @@ Files: share/icons/entries/*.png Copyright: 2003-2004, David Vignoni License: LGPL-2.1 +Files: src/crypto/salsa20/* +Copyright: is in public domain +License: - + Files: src/streams/qtiocompressor.*, src/streams/QtIOCompressor Copyright: 2009, Nokia Corporation and/or its subsidiary(-ies) License: LGPL-2.1 or GPL-3 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 302b753ab..fbd7ebe97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,15 @@ set(keepassx_SOURCES crypto/Crypto.cpp crypto/CryptoHash.cpp crypto/Random.cpp + crypto/salsa20/ecrypt-config.h + crypto/salsa20/ecrypt-machine.h + crypto/salsa20/ecrypt-portable.h + crypto/salsa20/ecrypt-sync.h + crypto/salsa20/salsa20.c crypto/SymmetricCipher.cpp + crypto/SymmetricCipherBackend.h + crypto/SymmetricCipherGcrypt.cpp + crypto/SymmetricCipherSalsa20.cpp format/KeePass2.h format/KeePass2Reader.cpp format/KeePass2Writer.cpp diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index bee190f81..856a597c1 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -65,6 +65,7 @@ Crypto::Crypto() void Crypto::init() { if (m_initalized) { + qWarning("Crypto::init: already initalized"); return; } diff --git a/src/crypto/SymmetricCipher.cpp b/src/crypto/SymmetricCipher.cpp index 90b77ce05..ecbb19887 100644 --- a/src/crypto/SymmetricCipher.cpp +++ b/src/crypto/SymmetricCipher.cpp @@ -17,33 +17,19 @@ #include "SymmetricCipher.h" -#include - -class SymmetricCipherPrivate -{ -public: - gcry_cipher_hd_t ctx; - SymmetricCipher::Direction direction; - QByteArray key; - QByteArray iv; - int blockSize; -}; +#include "SymmetricCipherGcrypt.h" +#include "SymmetricCipherSalsa20.h" SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv) - : d_ptr(new SymmetricCipherPrivate()) { - Q_D(SymmetricCipher); - - d->direction = direction; - d->key = key; - d->iv = iv; - - int algoGcrypt; - switch (algo) { case SymmetricCipher::Aes256: - algoGcrypt = GCRY_CIPHER_AES256; + m_backend = new SymmetricCipherGcrypt(); + break; + + case SymmetricCipher::Salsa20: + m_backend = new SymmetricCipherSalsa20(); break; default: @@ -51,102 +37,35 @@ SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCiphe break; } - int modeGcrypt; - - switch (mode) { - case SymmetricCipher::Ecb: - modeGcrypt = GCRY_CIPHER_MODE_ECB; - break; - - case SymmetricCipher::Cbc: - modeGcrypt = GCRY_CIPHER_MODE_CBC; - break; - - default: - Q_ASSERT(false); - break; - } - - gcry_error_t error; - - error = gcry_cipher_open(&d->ctx, algoGcrypt, modeGcrypt, 0); - Q_ASSERT(error == 0); // TODO real error checking - error = gcry_cipher_setkey(d->ctx, d->key.constData(), d->key.size()); - Q_ASSERT(error == 0); - error = gcry_cipher_setiv(d->ctx, d->iv.constData(), d->iv.size()); - Q_ASSERT(error == 0); - - size_t blockSizeT; - error = gcry_cipher_algo_info(algoGcrypt, GCRYCTL_GET_BLKLEN, 0, &blockSizeT); - Q_ASSERT(error == 0); - d->blockSize = blockSizeT; + m_backend->setAlgorithm(algo); + m_backend->setMode(mode); + m_backend->setDirection(direction); + m_backend->init(); + m_backend->setKey(key); + m_backend->setIv(iv); } SymmetricCipher::~SymmetricCipher() { - Q_D(SymmetricCipher); - - gcry_cipher_close(d->ctx); - - delete d_ptr; + delete m_backend; } QByteArray SymmetricCipher::process(const QByteArray& data) { - Q_D(SymmetricCipher); - - // TODO check block size - - QByteArray result; - result.resize(data.size()); - - gcry_error_t error; - - if (d->direction == SymmetricCipher::Decrypt) { - error = gcry_cipher_decrypt(d->ctx, result.data(), data.size(), data.constData(), data.size()); - } - else { - error = gcry_cipher_encrypt(d->ctx, result.data(), data.size(), data.constData(), data.size()); - } - - Q_ASSERT(error == 0); - - return result; + return m_backend->process(data); } void SymmetricCipher::processInPlace(QByteArray& data) { - Q_D(SymmetricCipher); - - // TODO check block size - - gcry_error_t error; - - if (d->direction == SymmetricCipher::Decrypt) { - error = gcry_cipher_decrypt(d->ctx, data.data(), data.size(), 0, 0); - } - else { - error = gcry_cipher_encrypt(d->ctx, data.data(), data.size(), 0, 0); - } - - Q_ASSERT(error == 0); + m_backend->processInPlace(data); } void SymmetricCipher::reset() { - Q_D(SymmetricCipher); - - gcry_error_t error; - - error = gcry_cipher_reset(d->ctx); - Q_ASSERT(error == 0); - error = gcry_cipher_setiv(d->ctx, d->iv.constData(), d->iv.size()); - Q_ASSERT(error == 0); + m_backend->reset(); } int SymmetricCipher::blockSize() const { - Q_D(const SymmetricCipher); - - return d->blockSize; + return m_backend->blockSize(); } diff --git a/src/crypto/SymmetricCipher.h b/src/crypto/SymmetricCipher.h index 6c1ca7205..2f744520b 100644 --- a/src/crypto/SymmetricCipher.h +++ b/src/crypto/SymmetricCipher.h @@ -20,20 +20,22 @@ #include -class SymmetricCipherPrivate; +class SymmetricCipherBackend; class SymmetricCipher { public: enum Algorithm { - Aes256 + Aes256, + Salsa20 }; enum Mode { Cbc, - Ecb + Ecb, + Stream }; enum Direction @@ -53,8 +55,8 @@ public: int blockSize() const; private: - SymmetricCipherPrivate* const d_ptr; - Q_DECLARE_PRIVATE(SymmetricCipher); + Q_DISABLE_COPY(SymmetricCipher) + SymmetricCipherBackend* m_backend; }; #endif // KEEPASSX_SYMMETRICCIPHER_H diff --git a/src/crypto/SymmetricCipherBackend.h b/src/crypto/SymmetricCipherBackend.h new file mode 100644 index 000000000..4b9467e67 --- /dev/null +++ b/src/crypto/SymmetricCipherBackend.h @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2010 Felix Geyer +* +* 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 or (at your option) +* version 3 of the License. +* +* 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, see . +*/ + +#ifndef KEEPASSX_SYMMETRICCIPHERBACKEND_H +#define KEEPASSX_SYMMETRICCIPHERBACKEND_H + +#include "SymmetricCipher.h" + +class SymmetricCipherBackend +{ +public: + virtual ~SymmetricCipherBackend() {}; + virtual void setAlgorithm(SymmetricCipher::Algorithm algo) = 0; + virtual void setMode(SymmetricCipher::Mode mode) = 0; + virtual void setDirection(SymmetricCipher::Direction direction) = 0; + virtual void init() = 0; + virtual void setKey(const QByteArray& key) = 0; + virtual void setIv(const QByteArray& iv) = 0; + + virtual QByteArray process(const QByteArray& data) = 0; + virtual void processInPlace(QByteArray& data) = 0; + + virtual void reset() = 0; + virtual int blockSize() const = 0; +}; + +#endif // KEEPASSX_SYMMETRICCIPHERBACKEND_H diff --git a/src/crypto/SymmetricCipherGcrypt.cpp b/src/crypto/SymmetricCipherGcrypt.cpp new file mode 100644 index 000000000..2b32bff17 --- /dev/null +++ b/src/crypto/SymmetricCipherGcrypt.cpp @@ -0,0 +1,137 @@ +/* +* Copyright (C) 2010 Felix Geyer +* +* 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 or (at your option) +* version 3 of the License. +* +* 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, see . +*/ + +#include "SymmetricCipherGcrypt.h" + +SymmetricCipherGcrypt::~SymmetricCipherGcrypt() +{ + gcry_cipher_close(m_ctx); +} + +void SymmetricCipherGcrypt::setAlgorithm(SymmetricCipher::Algorithm algo) +{ + switch (algo) { + case SymmetricCipher::Aes256: + m_algo = GCRY_CIPHER_AES256; + break; + + default: + Q_ASSERT(false); + break; + } +} + +void SymmetricCipherGcrypt::setMode(SymmetricCipher::Mode mode) +{ + switch (mode) { + case SymmetricCipher::Ecb: + m_mode = GCRY_CIPHER_MODE_ECB; + break; + + case SymmetricCipher::Cbc: + m_mode = GCRY_CIPHER_MODE_CBC; + break; + + default: + Q_ASSERT(false); + break; + } +} + +void SymmetricCipherGcrypt::setDirection(SymmetricCipher::Direction direction) +{ + m_direction = direction; +} + +void SymmetricCipherGcrypt::init() +{ + gcry_error_t error; + + error = gcry_cipher_open(&m_ctx, m_algo, m_mode, 0); + Q_ASSERT(error == 0); // TODO real error checking + + size_t blockSizeT; + error = gcry_cipher_algo_info(m_algo, GCRYCTL_GET_BLKLEN, 0, &blockSizeT); + Q_ASSERT(error == 0); + m_blockSize = blockSizeT; +} + +void SymmetricCipherGcrypt::setKey(const QByteArray& key) +{ + m_key = key; + gcry_error_t error = gcry_cipher_setkey(m_ctx, m_key.constData(), m_key.size()); + Q_ASSERT(error == 0); +} + +void SymmetricCipherGcrypt::setIv(const QByteArray& iv) +{ + m_iv = iv; + gcry_error_t error = gcry_cipher_setiv(m_ctx, m_iv.constData(), m_iv.size()); + Q_ASSERT(error == 0); +} + +QByteArray SymmetricCipherGcrypt::process(const QByteArray& data) +{ + // TODO check block size + + QByteArray result; + result.resize(data.size()); + + gcry_error_t error; + + if (m_direction == SymmetricCipher::Decrypt) { + error = gcry_cipher_decrypt(m_ctx, result.data(), data.size(), data.constData(), data.size()); + } + else { + error = gcry_cipher_encrypt(m_ctx, result.data(), data.size(), data.constData(), data.size()); + } + + Q_ASSERT(error == 0); + + return result; +} + +void SymmetricCipherGcrypt::processInPlace(QByteArray& data) +{ + // TODO check block size + + gcry_error_t error; + + if (m_direction == SymmetricCipher::Decrypt) { + error = gcry_cipher_decrypt(m_ctx, data.data(), data.size(), 0, 0); + } + else { + error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), 0, 0); + } + + Q_ASSERT(error == 0); +} + +void SymmetricCipherGcrypt::reset() +{ + gcry_error_t error; + + error = gcry_cipher_reset(m_ctx); + Q_ASSERT(error == 0); + error = gcry_cipher_setiv(m_ctx, m_iv.constData(), m_iv.size()); + Q_ASSERT(error == 0); +} + +int SymmetricCipherGcrypt::blockSize() const +{ + return m_blockSize; +} diff --git a/src/crypto/SymmetricCipherGcrypt.h b/src/crypto/SymmetricCipherGcrypt.h new file mode 100644 index 000000000..6ac0d1173 --- /dev/null +++ b/src/crypto/SymmetricCipherGcrypt.h @@ -0,0 +1,52 @@ +/* +* Copyright (C) 2010 Felix Geyer +* +* 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 or (at your option) +* version 3 of the License. +* +* 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, see . +*/ + +#ifndef KEEPASSX_SYMMETRICCIPHERGCRYPT_H +#define KEEPASSX_SYMMETRICCIPHERGCRYPT_H + +#include "SymmetricCipherBackend.h" + +#include + +class SymmetricCipherGcrypt : public SymmetricCipherBackend +{ +public: + ~SymmetricCipherGcrypt(); + void setAlgorithm(SymmetricCipher::Algorithm algo); + void setMode(SymmetricCipher::Mode mode); + void setDirection(SymmetricCipher::Direction direction); + void init(); + void setKey(const QByteArray& key); + void setIv(const QByteArray& iv); + + QByteArray process(const QByteArray& data); + void processInPlace(QByteArray& data); + + void reset(); + int blockSize() const; + +private: + gcry_cipher_hd_t m_ctx; + int m_algo; + int m_mode; + SymmetricCipher::Direction m_direction; + QByteArray m_key; + QByteArray m_iv; + int m_blockSize; +}; + +#endif // KEEPASSX_SYMMETRICCIPHERGCRYPT_H diff --git a/src/crypto/SymmetricCipherSalsa20.cpp b/src/crypto/SymmetricCipherSalsa20.cpp new file mode 100644 index 000000000..d5cc48729 --- /dev/null +++ b/src/crypto/SymmetricCipherSalsa20.cpp @@ -0,0 +1,88 @@ +/* +* Copyright (C) 2010 Felix Geyer +* +* 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 or (at your option) +* version 3 of the License. +* +* 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, see . +*/ + +#include "SymmetricCipherSalsa20.h" + +SymmetricCipherSalsa20::~SymmetricCipherSalsa20() +{ +} + +void SymmetricCipherSalsa20::setAlgorithm(SymmetricCipher::Algorithm algo) +{ + Q_ASSERT(algo == SymmetricCipher::Salsa20); +} + +void SymmetricCipherSalsa20::setMode(SymmetricCipher::Mode mode) +{ + Q_ASSERT(mode == SymmetricCipher::Stream); +} + +void SymmetricCipherSalsa20::setDirection(SymmetricCipher::Direction direction) +{ + Q_UNUSED(direction); +} + +void SymmetricCipherSalsa20::init() +{ +} + +void SymmetricCipherSalsa20::setKey(const QByteArray& key) +{ + Q_ASSERT( (key.size() == 16) || (key.size() == 32) ); + + m_key = key; + ECRYPT_keysetup(&m_ctx, reinterpret_cast(m_key.constData()), m_key.size()*8, 64); +} + +void SymmetricCipherSalsa20::setIv(const QByteArray& iv) +{ + Q_ASSERT(iv.size() == 8); + + m_iv = iv; + ECRYPT_ivsetup(&m_ctx, reinterpret_cast(m_iv.constData())); +} + +QByteArray SymmetricCipherSalsa20::process(const QByteArray& data) +{ + Q_ASSERT( (data.size() < blockSize()) || ((data.size() % blockSize())==0) ); + + QByteArray result; + result.resize(data.size()); + + ECRYPT_encrypt_bytes(&m_ctx, reinterpret_cast(data.constData()), + reinterpret_cast(result.data()), data.size()); + + return result; +} + +void SymmetricCipherSalsa20::processInPlace(QByteArray& data) +{ + Q_ASSERT( (data.size() < blockSize()) || ((data.size() % blockSize())==0) ); + + ECRYPT_encrypt_bytes(&m_ctx, reinterpret_cast(data.constData()), + reinterpret_cast(data.data()), data.size()); +} + +void SymmetricCipherSalsa20::reset() +{ + ECRYPT_ivsetup(&m_ctx, reinterpret_cast(m_iv.constData())); +} + +int SymmetricCipherSalsa20::blockSize() const +{ + return 64; +} diff --git a/src/crypto/SymmetricCipherSalsa20.h b/src/crypto/SymmetricCipherSalsa20.h new file mode 100644 index 000000000..af31c329e --- /dev/null +++ b/src/crypto/SymmetricCipherSalsa20.h @@ -0,0 +1,47 @@ +/* +* Copyright (C) 2010 Felix Geyer +* +* 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 or (at your option) +* version 3 of the License. +* +* 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, see . +*/ + +#ifndef KEEPASSX_SYMMETRICCIPHERSALSA20_H +#define KEEPASSX_SYMMETRICCIPHERSALSA20_H + +#include "SymmetricCipherBackend.h" +#include "salsa20/ecrypt-sync.h" + +class SymmetricCipherSalsa20 : public SymmetricCipherBackend +{ +public: + ~SymmetricCipherSalsa20(); + void setAlgorithm(SymmetricCipher::Algorithm algo); + void setMode(SymmetricCipher::Mode mode); + void setDirection(SymmetricCipher::Direction direction); + void init(); + void setKey(const QByteArray& key); + void setIv(const QByteArray& iv); + + QByteArray process(const QByteArray& data); + void processInPlace(QByteArray& data); + + void reset(); + int blockSize() const; + +private: + ECRYPT_ctx m_ctx; + QByteArray m_key; + QByteArray m_iv; +}; + +#endif // KEEPASSX_SYMMETRICCIPHERSALSA20_H diff --git a/src/crypto/salsa20/ecrypt-config.h b/src/crypto/salsa20/ecrypt-config.h new file mode 100644 index 000000000..57c33a42c --- /dev/null +++ b/src/crypto/salsa20/ecrypt-config.h @@ -0,0 +1,297 @@ +/* ecrypt-config.h */ + +/* *** Normally, it should not be necessary to edit this file. *** */ + +#ifndef ECRYPT_CONFIG +#define ECRYPT_CONFIG + +/* ------------------------------------------------------------------------- */ + +/* Guess the endianness of the target architecture. */ + +/* + * The LITTLE endian machines: + */ +#if defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__x86_64) /* x86_64 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(__sparc) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__powerpc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__hppa) /* HP-PA */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined (_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit + * integers. + * + * Note: to enable 64-bit types on 32-bit compilers, it might be + * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc + * -std=c99), or to allow compiler-specific extensions. + */ + +#include + +/* --- check char --- */ + +#if (UCHAR_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) + +#if (UCHAR_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UCHAR_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T char +#define U16C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T char +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check short --- */ + +#if (USHRT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T short +#define U8C(v) (v##U) + +#if (USHRT_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (USHRT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T short +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check int --- */ + +#if (UINT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T int +#define U8C(v) (v##U) + +#if (ULONG_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UINT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T int +#define U16C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T int +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long --- */ + +#if (ULONG_MAX / 0xFUL > 0xFUL) +#ifndef I8T +#define I8T long +#define U8C(v) (v##UL) + +#if (ULONG_MAX == 0xFFUL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULONG_MAX / 0xFFUL > 0xFFUL) +#ifndef I16T +#define I16T long +#define U16C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) +#ifndef I64T +#define I64T long +#define U64C(v) (v##UL) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long long --- */ + +#ifdef ULLONG_MAX + +#if (ULLONG_MAX / 0xFULL > 0xFULL) +#ifndef I8T +#define I8T long long +#define U8C(v) (v##ULL) + +#if (ULLONG_MAX == 0xFFULL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULLONG_MAX / 0xFFULL > 0xFFULL) +#ifndef I16T +#define I16T long long +#define U16C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) +#ifndef I32T +#define I32T long long +#define U32C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +#endif +#endif +#endif +#endif + +#endif + +/* --- check __int64 --- */ + +#if !defined(__STDC__) && defined(_UI64_MAX) + +#ifndef I64T +#define I64T __int64 +#define U64C(v) (v##ui64) +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +/* find the largest type on this platform (used for alignment) */ + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) + +#include +#define MAXT __m128 + +#elif defined(__MMX__) + +#include +#define MAXT __m64 + +#elif defined(__ALTIVEC__) + +#define MAXT __vector int + +#else + +#define MAXT long + +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/src/crypto/salsa20/ecrypt-machine.h b/src/crypto/salsa20/ecrypt-machine.h new file mode 100644 index 000000000..d006bedec --- /dev/null +++ b/src/crypto/salsa20/ecrypt-machine.h @@ -0,0 +1,49 @@ +/* ecrypt-machine.h */ + +/* + * This file is included by 'ecrypt-portable.h'. It allows to override + * the default macros for specific platforms. Please carefully check + * the machine code generated by your compiler (with optimisations + * turned on) before deciding to edit this file. + */ + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) + +#define ECRYPT_MACHINE_ROT + +#if (defined(WIN32) && defined(_MSC_VER)) + +#undef ROTL32 +#undef ROTR32 +#undef ROTL64 +#undef ROTR64 + +#include + +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#pragma intrinsic(_lrotr) + +#define ROTL32(v, n) _lrotl(v, n) +#define ROTR32(v, n) _lrotr(v, n) +#define ROTL64(v, n) _rotl64(v, n) +#define ROTR64(v, n) _rotr64(v, n) + +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) + +#define ECRYPT_MACHINE_SWAP + +/* + * If you want to overwrite the default swap macros, put it here. And so on. + */ + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/src/crypto/salsa20/ecrypt-portable.h b/src/crypto/salsa20/ecrypt-portable.h new file mode 100644 index 000000000..438a464a7 --- /dev/null +++ b/src/crypto/salsa20/ecrypt-portable.h @@ -0,0 +1,310 @@ +/* ecrypt-portable.h */ + +/* + * WARNING: the conversions defined below are implemented as macros, + * and should be used carefully. They should NOT be used with + * parameters which perform some action. E.g., the following two lines + * are not equivalent: + * + * 1) ++x; y = ROTL32(x, n); + * 2) y = ROTL32(++x, n); + */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_PORTABLE +#define ECRYPT_PORTABLE + +#include "ecrypt-config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +/* + * The following macros are used to obtain exact-width results. + */ + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U16V(v) ((u16)(v) & U16C(0xFFFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) +#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF)) + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return words with their bits rotated over n + * positions to the left/right. + */ + +#define ECRYPT_DEFAULT_ROT + +#define ROTL8(v, n) \ + (U8V((v) << (n)) | ((v) >> (8 - (n)))) + +#define ROTL16(v, n) \ + (U16V((v) << (n)) | ((v) >> (16 - (n)))) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define ROTL64(v, n) \ + (U64V((v) << (n)) | ((v) >> (64 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return a word with bytes in reverse order. + */ + +#define ECRYPT_DEFAULT_SWAP + +#define SWAP16(v) \ + ROTL16(v, 8) + +#define SWAP32(v) \ + ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ + (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#ifdef ECRYPT_NATIVE64 +#define SWAP64(v) \ + ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \ + (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ + (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \ + (ROTL64(v, 56) & U64C(0xFF000000FF000000))) +#else +#define SWAP64(v) \ + (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) +#endif + +#include "ecrypt-machine.h" + +#define ECRYPT_DEFAULT_WTOW + +#ifdef ECRYPT_LITTLE_ENDIAN +#define U16TO16_LITTLE(v) (v) +#define U32TO32_LITTLE(v) (v) +#define U64TO64_LITTLE(v) (v) + +#define U16TO16_BIG(v) SWAP16(v) +#define U32TO32_BIG(v) SWAP32(v) +#define U64TO64_BIG(v) SWAP64(v) +#endif + +#ifdef ECRYPT_BIG_ENDIAN +#define U16TO16_LITTLE(v) SWAP16(v) +#define U32TO32_LITTLE(v) SWAP32(v) +#define U64TO64_LITTLE(v) SWAP64(v) + +#define U16TO16_BIG(v) (v) +#define U32TO32_BIG(v) (v) +#define U64TO64_BIG(v) (v) +#endif + +#include "ecrypt-machine.h" + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ + +#define ECRYPT_DEFAULT_BTOW + +#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) + +#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) + +#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) +#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) +#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) + +#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) + +#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) +#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) +#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) + +#else + +#define U8TO16_LITTLE(p) \ + (((u16)((p)[0]) ) | \ + ((u16)((p)[1]) << 8)) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_LITTLE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) +#else +#define U8TO64_LITTLE(p) \ + ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) +#endif + +#define U8TO16_BIG(p) \ + (((u16)((p)[0]) << 8) | \ + ((u16)((p)[1]) )) + +#define U8TO32_BIG(p) \ + (((u32)((p)[0]) << 24) | \ + ((u32)((p)[1]) << 16) | \ + ((u32)((p)[2]) << 8) | \ + ((u32)((p)[3]) )) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_BIG(p) \ + (((u64)((p)[0]) << 56) | \ + ((u64)((p)[1]) << 48) | \ + ((u64)((p)[2]) << 40) | \ + ((u64)((p)[3]) << 32) | \ + ((u64)((p)[4]) << 24) | \ + ((u64)((p)[5]) << 16) | \ + ((u64)((p)[6]) << 8) | \ + ((u64)((p)[7]) )) +#else +#define U8TO64_BIG(p) \ + (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) +#endif + +#define U16TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + (p)[4] = U8V((v) >> 32); \ + (p)[5] = U8V((v) >> 40); \ + (p)[6] = U8V((v) >> 48); \ + (p)[7] = U8V((v) >> 56); \ + } while (0) +#else +#define U64TO8_LITTLE(p, v) \ + do { \ + U32TO8_LITTLE((p), U32V((v) )); \ + U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ + } while (0) +#endif + +#define U16TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 24); \ + (p)[1] = U8V((v) >> 16); \ + (p)[2] = U8V((v) >> 8); \ + (p)[3] = U8V((v) ); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 56); \ + (p)[1] = U8V((v) >> 48); \ + (p)[2] = U8V((v) >> 40); \ + (p)[3] = U8V((v) >> 32); \ + (p)[4] = U8V((v) >> 24); \ + (p)[5] = U8V((v) >> 16); \ + (p)[6] = U8V((v) >> 8); \ + (p)[7] = U8V((v) ); \ + } while (0) +#else +#define U64TO8_BIG(p, v) \ + do { \ + U32TO8_BIG((p), U32V((v) >> 32)); \ + U32TO8_BIG((p) + 4, U32V((v) )); \ + } while (0) +#endif + +#endif + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n)) + +#define ALIGN(t, v, n) \ + union { t b[n]; MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; } v + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/src/crypto/salsa20/ecrypt-sync.h b/src/crypto/salsa20/ecrypt-sync.h new file mode 100644 index 000000000..245793e19 --- /dev/null +++ b/src/crypto/salsa20/ecrypt-sync.h @@ -0,0 +1,287 @@ +/* ecrypt-sync.h */ + +/* + * Header file for synchronous stream ciphers without authentication + * mechanism. + * + * *** Please only edit parts marked with "[edit]". *** + */ + +#ifndef ECRYPT_SYNC +#define ECRYPT_SYNC + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecrypt-portable.h" + +/* ------------------------------------------------------------------------- */ + +/* Cipher parameters */ + +/* + * The name of your cipher. + */ +#define ECRYPT_NAME "Salsa20" /* [edit] */ +#define ECRYPT_PROFILE "S!_H." + +/* + * Specify which key and IV sizes are supported by your cipher. A user + * should be able to enumerate the supported sizes by running the + * following code: + * + * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) + * { + * keysize = ECRYPT_KEYSIZE(i); + * + * ... + * } + * + * All sizes are in bits. + */ + +#define ECRYPT_MAXKEYSIZE 256 /* [edit] */ +#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */ + +#define ECRYPT_MAXIVSIZE 64 /* [edit] */ +#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */ + +/* ------------------------------------------------------------------------- */ + +/* Data structures */ + +/* + * ECRYPT_ctx is the structure containing the representation of the + * internal state of your cipher. + */ + +typedef struct +{ + u32 input[16]; /* could be compressed */ + /* + * [edit] + * + * Put here all state variable needed during the encryption process. + */ +} ECRYPT_ctx; + +/* ------------------------------------------------------------------------- */ + +/* Mandatory functions */ + +/* + * Key and message independent initialization. This function will be + * called once when the program starts (e.g., to build expanded S-box + * tables). + */ +void ECRYPT_init(); + +/* + * Key setup. It is the user's responsibility to select the values of + * keysize and ivsize from the set of supported values specified + * above. + */ +void ECRYPT_keysetup( + ECRYPT_ctx* ctx, + const u8* key, + u32 keysize, /* Key size in bits. */ + u32 ivsize); /* IV size in bits. */ + +/* + * IV setup. After having called ECRYPT_keysetup(), the user is + * allowed to call ECRYPT_ivsetup() different times in order to + * encrypt/decrypt different messages with the same key but different + * IV's. + */ +void ECRYPT_ivsetup( + ECRYPT_ctx* ctx, + const u8* iv); + +/* + * Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the ECRYPT_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of ECRYPT_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called ECRYPT_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * ECRYPT_keysetup(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_bytes(); + * + * The following sequence is not: + * + * ECRYPT_keysetup(); + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * ECRYPT_encrypt_blocks(); + */ + +void ECRYPT_encrypt_bytes( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 msglen); /* Message length in bytes. */ + +void ECRYPT_decrypt_bytes( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 msglen); /* Message length in bytes. */ + +/* ------------------------------------------------------------------------- */ + +/* Optional features */ + +/* + * For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. If your cipher cannot provide this function + * (e.g., because it is not strictly a synchronous cipher), please + * reset the ECRYPT_GENERATES_KEYSTREAM flag. + */ + +#define ECRYPT_GENERATES_KEYSTREAM +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_bytes( + ECRYPT_ctx* ctx, + u8* keystream, + u32 length); /* Length of keystream in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional optimizations */ + +/* + * By default, the functions in this section are implemented using + * calls to functions declared above. However, you might want to + * implement them differently for performance reasons. + */ + +/* + * All-in-one encryption/decryption of (short) packets. + * + * The default definitions of these functions can be found in + * "ecrypt-sync.c". If you want to implement them differently, please + * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. + */ +#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */ + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen); + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen); + +/* + * Encryption/decryption of blocks. + * + * By default, these functions are defined as macros. If you want to + * provide a different implementation, please undef the + * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions + * declared below. + */ + +#define ECRYPT_BLOCKLENGTH 64 /* [edit] */ + +#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */ +#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ + ECRYPT_keystream_bytes(ctx, keystream, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#endif + +#else + +void ECRYPT_encrypt_blocks( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 blocks); /* Message length in blocks. */ + +void ECRYPT_decrypt_blocks( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 blocks); /* Message length in blocks. */ + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_blocks( + ECRYPT_ctx* ctx, + const u8* keystream, + u32 blocks); /* Keystream length in blocks. */ + +#endif + +#endif + +/* + * If your cipher can be implemented in different ways, you can use + * the ECRYPT_VARIANT parameter to allow the user to choose between + * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please + * only use this possibility if you really think it could make a + * significant difference and keep the number of variants + * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than + * 10). Note also that all variants should have exactly the same + * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). + */ +#define ECRYPT_MAXVARIANT 1 /* [edit] */ + +#ifndef ECRYPT_VARIANT +#define ECRYPT_VARIANT 1 +#endif + +#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT) +#error this variant does not exist +#endif + +/* ------------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/crypto/salsa20/salsa20.c b/src/crypto/salsa20/salsa20.c new file mode 100644 index 000000000..74f806cad --- /dev/null +++ b/src/crypto/salsa20/salsa20.c @@ -0,0 +1,133 @@ +/* +salsa20-ref.c version 20051118 +D. J. Bernstein +Public domain. +*/ + +#include "ecrypt-sync.h" + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +static void salsa20_wordtobyte(u8 output[64],const u32 input[16]) +{ + u32 x[16]; + int i; + + for (i = 0;i < 16;++i) x[i] = input[i]; + for (i = 20;i > 0;i -= 2) { + x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7)); + x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9)); + x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13)); + x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18)); + x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7)); + x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9)); + x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13)); + x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18)); + x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7)); + x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9)); + x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13)); + x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18)); + x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7)); + x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9)); + x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13)); + x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18)); + x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7)); + x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9)); + x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13)); + x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18)); + x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7)); + x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9)); + x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13)); + x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18)); + x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7)); + x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9)); + x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13)); + x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18)); + x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7)); + x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9)); + x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13)); + x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18)); + } + for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]); + for (i = 0;i < 16;++i) U32TO8_LITTLE(output + 4 * i,x[i]); +} + +void ECRYPT_init(void) +{ + return; +} + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + (void)ivbits; + const char *constants; + + x->input[1] = U8TO32_LITTLE(k + 0); + x->input[2] = U8TO32_LITTLE(k + 4); + x->input[3] = U8TO32_LITTLE(k + 8); + x->input[4] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[11] = U8TO32_LITTLE(k + 0); + x->input[12] = U8TO32_LITTLE(k + 4); + x->input[13] = U8TO32_LITTLE(k + 8); + x->input[14] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[5] = U8TO32_LITTLE(constants + 4); + x->input[10] = U8TO32_LITTLE(constants + 8); + x->input[15] = U8TO32_LITTLE(constants + 12); +} + +void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) +{ + x->input[6] = U8TO32_LITTLE(iv + 0); + x->input[7] = U8TO32_LITTLE(iv + 4); + x->input[8] = 0; + x->input[9] = 0; +} + +void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u8 output[64]; + u32 i; + + if (!bytes) return; + for (;;) { + salsa20_wordtobyte(output,x->input); + x->input[8] = PLUSONE(x->input[8]); + if (!x->input[8]) { + x->input[9] = PLUSONE(x->input[9]); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + if (bytes <= 64) { + for (i = 0;i < bytes;++i) c[i] = m[i] ^ output[i]; + return; + } + for (i = 0;i < 64;++i) c[i] = m[i] ^ output[i]; + bytes -= 64; + c += 64; + m += 64; + } +} + +void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes) +{ + ECRYPT_encrypt_bytes(x,c,m,bytes); +} + +void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes) +{ + u32 i; + for (i = 0;i < bytes;++i) stream[i] = 0; + ECRYPT_encrypt_bytes(x,stream,stream,bytes); +} diff --git a/tests/TestSymmetricCipher.cpp b/tests/TestSymmetricCipher.cpp index bb3ff4e7a..923e0c550 100644 --- a/tests/TestSymmetricCipher.cpp +++ b/tests/TestSymmetricCipher.cpp @@ -30,6 +30,7 @@ private Q_SLOTS: void initTestCase(); void testAes256CbcEncryption(); void testAes256CbcDecryption(); + void testSalsa20(); }; void TestSymmetricCipher::initTestCase() @@ -115,6 +116,59 @@ void TestSymmetricCipher::testAes256CbcDecryption() plainText); } +void TestSymmetricCipher::testSalsa20() +{ + // http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup + + QByteArray key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); + QByteArray iv = QByteArray::fromHex("0000000000000000"); + + SymmetricCipher cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt, key, iv); + + QByteArray cipherTextA; + for (int i=0; i<8; i++) { + cipherTextA.append(cipher.process(QByteArray(64, '\0'))); + } + cipher.reset(); + + QByteArray cipherTextB = cipher.process(QByteArray(512, '\0')); + cipher.reset(); + + QByteArray expectedCipherText1; + expectedCipherText1.append(QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F")); + expectedCipherText1.append(QByteArray::fromHex("5D27DC246F75B9AD8760C8C39DFD8749")); + expectedCipherText1.append(QByteArray::fromHex("2D3B76D5D9637F009EADA14458A52DFB")); + expectedCipherText1.append(QByteArray::fromHex("09815337E72672681DDDC24633750D83")); + + QByteArray expectedCipherText2; + expectedCipherText2.append(QByteArray::fromHex("DBBA0683DF48C335A9802EEF02522563")); + expectedCipherText2.append(QByteArray::fromHex("54C9F763C3FDE19131A6BB7B85040624")); + expectedCipherText2.append(QByteArray::fromHex("B1D6CD4BF66D16F7482236C8602A6D58")); + expectedCipherText2.append(QByteArray::fromHex("505EEDCCA0B77AED574AB583115124B9")); + + QByteArray expectedCipherText3; + expectedCipherText3.append(QByteArray::fromHex("F0C5F98BAE05E019764EF6B65E0694A9")); + expectedCipherText3.append(QByteArray::fromHex("04CB9EC9C10C297B1AB1A6052365BB78")); + expectedCipherText3.append(QByteArray::fromHex("E55D3C6CB9F06184BA7D425A92E7E987")); + expectedCipherText3.append(QByteArray::fromHex("757FC5D9AFD7082418DD64125CA6F2B6")); + + QByteArray expectedCipherText4; + expectedCipherText4.append(QByteArray::fromHex("5A5FB5C8F0AFEA471F0318A4A2792F7A")); + expectedCipherText4.append(QByteArray::fromHex("A5C67B6D6E0F0DDB79961C34E3A564BA")); + expectedCipherText4.append(QByteArray::fromHex("2EECE78D9AFF45E510FEAB1030B102D3")); + expectedCipherText4.append(QByteArray::fromHex("9DFCECB77F5798F7D2793C0AB09C7A04")); + + QCOMPARE(cipherTextA.mid(0, 64), expectedCipherText1); + QCOMPARE(cipherTextA.mid(192, 64), expectedCipherText2); + QCOMPARE(cipherTextA.mid(256, 64), expectedCipherText3); + QCOMPARE(cipherTextA.mid(448, 64), expectedCipherText4); + + QCOMPARE(cipherTextB.mid(0, 64), expectedCipherText1); + QCOMPARE(cipherTextB.mid(192, 64), expectedCipherText2); + QCOMPARE(cipherTextB.mid(256, 64), expectedCipherText3); + QCOMPARE(cipherTextB.mid(448, 64), expectedCipherText4); +} + QTEST_MAIN(TestSymmetricCipher); #include "TestSymmetricCipher.moc"