Add Salsa20 cipher.

Restructure SymmetricCipher implementation to allow multiple backends.
This commit is contained in:
Felix Geyer 2010-11-21 16:19:27 +01:00
parent 3b9982c0a3
commit a428464573
16 changed files with 1533 additions and 104 deletions

View File

@ -30,6 +30,10 @@ Files: share/icons/entries/*.png
Copyright: 2003-2004, David Vignoni <david@icon-king.com> Copyright: 2003-2004, David Vignoni <david@icon-king.com>
License: LGPL-2.1 License: LGPL-2.1
Files: src/crypto/salsa20/*
Copyright: is in public domain
License: -
Files: src/streams/qtiocompressor.*, src/streams/QtIOCompressor Files: src/streams/qtiocompressor.*, src/streams/QtIOCompressor
Copyright: 2009, Nokia Corporation and/or its subsidiary(-ies) Copyright: 2009, Nokia Corporation and/or its subsidiary(-ies)
License: LGPL-2.1 or GPL-3 License: LGPL-2.1 or GPL-3

View File

@ -29,7 +29,15 @@ set(keepassx_SOURCES
crypto/Crypto.cpp crypto/Crypto.cpp
crypto/CryptoHash.cpp crypto/CryptoHash.cpp
crypto/Random.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/SymmetricCipher.cpp
crypto/SymmetricCipherBackend.h
crypto/SymmetricCipherGcrypt.cpp
crypto/SymmetricCipherSalsa20.cpp
format/KeePass2.h format/KeePass2.h
format/KeePass2Reader.cpp format/KeePass2Reader.cpp
format/KeePass2Writer.cpp format/KeePass2Writer.cpp

View File

@ -65,6 +65,7 @@ Crypto::Crypto()
void Crypto::init() void Crypto::init()
{ {
if (m_initalized) { if (m_initalized) {
qWarning("Crypto::init: already initalized");
return; return;
} }

View File

@ -17,33 +17,19 @@
#include "SymmetricCipher.h" #include "SymmetricCipher.h"
#include <gcrypt.h> #include "SymmetricCipherGcrypt.h"
#include "SymmetricCipherSalsa20.h"
class SymmetricCipherPrivate
{
public:
gcry_cipher_hd_t ctx;
SymmetricCipher::Direction direction;
QByteArray key;
QByteArray iv;
int blockSize;
};
SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv) 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) { switch (algo) {
case SymmetricCipher::Aes256: case SymmetricCipher::Aes256:
algoGcrypt = GCRY_CIPHER_AES256; m_backend = new SymmetricCipherGcrypt();
break;
case SymmetricCipher::Salsa20:
m_backend = new SymmetricCipherSalsa20();
break; break;
default: default:
@ -51,102 +37,35 @@ SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCiphe
break; break;
} }
int modeGcrypt; m_backend->setAlgorithm(algo);
m_backend->setMode(mode);
switch (mode) { m_backend->setDirection(direction);
case SymmetricCipher::Ecb: m_backend->init();
modeGcrypt = GCRY_CIPHER_MODE_ECB; m_backend->setKey(key);
break; m_backend->setIv(iv);
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;
} }
SymmetricCipher::~SymmetricCipher() SymmetricCipher::~SymmetricCipher()
{ {
Q_D(SymmetricCipher); delete m_backend;
gcry_cipher_close(d->ctx);
delete d_ptr;
} }
QByteArray SymmetricCipher::process(const QByteArray& data) QByteArray SymmetricCipher::process(const QByteArray& data)
{ {
Q_D(SymmetricCipher); return m_backend->process(data);
// 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;
} }
void SymmetricCipher::processInPlace(QByteArray& data) void SymmetricCipher::processInPlace(QByteArray& data)
{ {
Q_D(SymmetricCipher); m_backend->processInPlace(data);
// 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);
} }
void SymmetricCipher::reset() void SymmetricCipher::reset()
{ {
Q_D(SymmetricCipher); m_backend->reset();
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);
} }
int SymmetricCipher::blockSize() const int SymmetricCipher::blockSize() const
{ {
Q_D(const SymmetricCipher); return m_backend->blockSize();
return d->blockSize;
} }

View File

@ -20,20 +20,22 @@
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
class SymmetricCipherPrivate; class SymmetricCipherBackend;
class SymmetricCipher class SymmetricCipher
{ {
public: public:
enum Algorithm enum Algorithm
{ {
Aes256 Aes256,
Salsa20
}; };
enum Mode enum Mode
{ {
Cbc, Cbc,
Ecb Ecb,
Stream
}; };
enum Direction enum Direction
@ -53,8 +55,8 @@ public:
int blockSize() const; int blockSize() const;
private: private:
SymmetricCipherPrivate* const d_ptr; Q_DISABLE_COPY(SymmetricCipher)
Q_DECLARE_PRIVATE(SymmetricCipher); SymmetricCipherBackend* m_backend;
}; };
#endif // KEEPASSX_SYMMETRICCIPHER_H #endif // KEEPASSX_SYMMETRICCIPHER_H

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -0,0 +1,137 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_SYMMETRICCIPHERGCRYPT_H
#define KEEPASSX_SYMMETRICCIPHERGCRYPT_H
#include "SymmetricCipherBackend.h"
#include <gcrypt.h>
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

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<const u8*>(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<const u8*>(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<const u8*>(data.constData()),
reinterpret_cast<u8*>(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<const u8*>(data.constData()),
reinterpret_cast<u8*>(data.data()), data.size());
}
void SymmetricCipherSalsa20::reset()
{
ECRYPT_ivsetup(&m_ctx, reinterpret_cast<const u8*>(m_iv.constData()));
}
int SymmetricCipherSalsa20::blockSize() const
{
return 64;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -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 <limits.h>
/* --- 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 <xmmintrin.h>
#define MAXT __m128
#elif defined(__MMX__)
#include <mmintrin.h>
#define MAXT __m64
#elif defined(__ALTIVEC__)
#define MAXT __vector int
#else
#define MAXT long
#endif
/* ------------------------------------------------------------------------- */
#endif

View File

@ -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 <stdlib.h>
#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
/* ------------------------------------------------------------------------- */

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -30,6 +30,7 @@ private Q_SLOTS:
void initTestCase(); void initTestCase();
void testAes256CbcEncryption(); void testAes256CbcEncryption();
void testAes256CbcDecryption(); void testAes256CbcDecryption();
void testSalsa20();
}; };
void TestSymmetricCipher::initTestCase() void TestSymmetricCipher::initTestCase()
@ -115,6 +116,59 @@ void TestSymmetricCipher::testAes256CbcDecryption()
plainText); 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); QTEST_MAIN(TestSymmetricCipher);
#include "TestSymmetricCipher.moc" #include "TestSymmetricCipher.moc"