Commit bb6d1283 authored by Simon Josefsson's avatar Simon Josefsson Committed by Niels Möller

Implemented the Salsa20 cipher.

parent 5d3b155f
2012-03-29 Niels Möller <nisse@lysator.liu.se>
Implementation of Salsa20, contributed by Simon Josefsson.
* salsa20.h: New file.
* salsa20.c: New file.
* Makefile.in (nettle_SOURCES): Added salsa20.c
(HEADERS): Added salsa20.h.
* testsuite/Makefile.in (TS_NETTLE_SOURCES): Added salsa20-test.c.
* testsuite/salsa20-test.c: New test case.
* Makefile.in (soname links): Adding missing space before ].
2012-03-23 Niels Möller <nisse@lysator.liu.se>
......
......@@ -79,6 +79,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
md2.c md2-meta.c md4.c md4-meta.c \
md5.c md5-compress.c md5-compat.c md5-meta.c \
ripemd160.c ripemd160-compress.c ripemd160-meta.c \
salsa20.c \
sha1.c sha1-compress.c sha1-meta.c \
sha256.c sha256-compress.c sha224-meta.c sha256-meta.c \
sha512.c sha512-compress.c sha384-meta.c sha512-meta.c \
......@@ -125,7 +126,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
memxor.h \
nettle-meta.h nettle-types.h \
pgp.h pkcs1.h realloc.h ripemd160.h rsa.h rsa-compat.h \
sexp.h \
salsa20.h sexp.h \
serpent.h sha.h twofish.h \
yarrow.h
......
/* salsa20.c
*
* The Salsa20 stream cipher.
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2012 Simon Josefsson
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
/* Based on:
salsa20-ref.c version 20051118
D. J. Bernstein
Public domain.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include "salsa20.h"
#define ROTL32(x,n) ((((x))<<(n)) | (((x))>>(32-(n))))
#define SWAP32(v) \
((ROTL32(v, 8) & 0x00FF00FFUL) | \
(ROTL32(v, 24) & 0xFF00FF00UL))
#ifdef WORDS_BIGENDIAN
#define U32TO32_LITTLE(v) SWAP32(v)
#else
#define U32TO32_LITTLE(v) (v)
#endif
#define U8TO32_LITTLE(p) U32TO32_LITTLE(((uint32_t*)(p))[0])
#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = U32TO32_LITTLE(v))
/*
salsa20-ref.c version 20051118
D. J. Bernstein
Public domain.
*/
#define ROTATE(v,c) (ROTL32(v,c))
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) ((v) + (w))
#define PLUSONE(v) (PLUS((v),1))
static void salsa20_wordtobyte(uint8_t output[64],const uint32_t input[16])
{
uint32_t 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]);
}
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
void
salsa20_set_key(struct salsa20_ctx *ctx,
unsigned length, const uint8_t *key)
{
const char *constants;
assert (length == SALSA20_MIN_KEY_SIZE || length == SALSA20_MAX_KEY_SIZE);
ctx->input[1] = U8TO32_LITTLE(key + 0);
ctx->input[2] = U8TO32_LITTLE(key + 4);
ctx->input[3] = U8TO32_LITTLE(key + 8);
ctx->input[4] = U8TO32_LITTLE(key + 12);
if (length == SALSA20_MAX_KEY_SIZE) { /* recommended */
key += 16;
constants = sigma;
} else { /* kbits == 128 */
constants = tau;
}
ctx->input[11] = U8TO32_LITTLE(key + 0);
ctx->input[12] = U8TO32_LITTLE(key + 4);
ctx->input[13] = U8TO32_LITTLE(key + 8);
ctx->input[14] = U8TO32_LITTLE(key + 12);
ctx->input[0] = U8TO32_LITTLE(constants + 0);
ctx->input[5] = U8TO32_LITTLE(constants + 4);
ctx->input[10] = U8TO32_LITTLE(constants + 8);
ctx->input[15] = U8TO32_LITTLE(constants + 12);
}
void
salsa20_set_iv(struct salsa20_ctx *ctx, unsigned length, const uint8_t *iv)
{
assert (length == SALSA20_IV_SIZE);
ctx->input[6] = U8TO32_LITTLE(iv + 0);
ctx->input[7] = U8TO32_LITTLE(iv + 4);
ctx->input[8] = 0;
ctx->input[9] = 0;
}
void
salsa20_crypt(struct salsa20_ctx *ctx,
unsigned length,
uint8_t *c,
const uint8_t *m)
{
uint8_t output[64];
unsigned i;
if (!length) return;
for (;;) {
salsa20_wordtobyte(output,ctx->input);
ctx->input[8] = PLUSONE(ctx->input[8]);
if (!ctx->input[8]) {
ctx->input[9] = PLUSONE(ctx->input[9]);
/* stopping at 2^70 length per nonce is user's responsibility */
}
if (length <= 64) {
for (i = 0;i < length;++i) c[i] = m[i] ^ output[i];
return;
}
for (i = 0;i < 64;++i) c[i] = m[i] ^ output[i];
length -= 64;
c += 64;
m += 64;
}
}
/* salsa20.h
*
* The Salsa20 stream cipher.
*/
/* nettle, low-level cryptographics library
*
* Copyright (C) 2012 Simon Josefsson
* Copyright (C) 2001 Niels Möller
*
* The nettle library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The nettle library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the nettle library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef NETTLE_SALSA20_H_INCLUDED
#define NETTLE_SALSA20_H_INCLUDED
#include "nettle-types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Name mangling */
#define salsa20_set_key nettle_salsa20_set_key
#define salsa20_set_iv nettle_salsa20_set_iv
#define salsa20_crypt nettle_salsa20_crypt
/* Minimum and maximum keysizes, and a reasonable default. In
* octets.*/
#define SALSA20_MIN_KEY_SIZE 16
#define SALSA20_MAX_KEY_SIZE 32
#define SALSA20_KEY_SIZE 32
#define SALSA20_IV_SIZE 8
struct salsa20_ctx
{
uint32_t input[16];
};
void
salsa20_set_key(struct salsa20_ctx *ctx,
unsigned length, const uint8_t *key);
void
salsa20_set_iv(struct salsa20_ctx *ctx,
unsigned length, const uint8_t *iv);
void
salsa20_crypt(struct salsa20_ctx *ctx,
unsigned length, uint8_t *dst,
const uint8_t *src);
#ifdef __cplusplus
}
#endif
#endif /* NETTLE_SALSA20_H_INCLUDED */
......@@ -36,6 +36,7 @@
/rsa-keygen-test
/rsa-test
/rsa2sexp-test
/salsa20-test
/serpent-test
/sexp-format-test
/sexp-test
......
......@@ -49,6 +49,9 @@ memxor-test$(EXEEXT): memxor-test.$(OBJEXT)
ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
$(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT)
salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
$(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
sha1-test$(EXEEXT): sha1-test.$(OBJEXT)
$(LINK) sha1-test.$(OBJEXT) $(TEST_OBJS) -o sha1-test$(EXEEXT)
......
......@@ -18,6 +18,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
md2-test.c md4-test.c md5-test.c md5-compat-test.c \
memxor-test.c \
ripemd160-test.c \
salsa20-test.c \
sha1-test.c sha224-test.c sha256-test.c \
sha384-test.c sha512-test.c \
serpent-test.c twofish-test.c \
......
#include "testutils.h"
#include "salsa20.h"
static void
test_salsa20(unsigned key_length,
const uint8_t *key,
unsigned iv_length,
const uint8_t *iv,
unsigned length,
const uint8_t *cleartext,
const uint8_t *ciphertext)
{
struct salsa20_ctx ctx;
uint8_t *data = xalloc(length);
salsa20_set_key(&ctx, key_length, key);
salsa20_set_iv(&ctx, iv_length, iv);
salsa20_crypt(&ctx, length, data, cleartext);
if (!MEMEQ(length, data, ciphertext))
{
fprintf(stderr, "Encrypt failed:\nInput:");
print_hex(length, cleartext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
print_hex(length, ciphertext);
fprintf(stderr, "\n");
FAIL();
}
salsa20_set_key(&ctx, key_length, key);
salsa20_set_iv(&ctx, iv_length, iv);
salsa20_crypt(&ctx, length, data, data);
if (!MEMEQ(length, data, cleartext))
{
fprintf(stderr, "Decrypt failed:\nInput:");
print_hex(length, ciphertext);
fprintf(stderr, "\nOutput: ");
print_hex(length, data);
fprintf(stderr, "\nExpected:");
print_hex(length, cleartext);
fprintf(stderr, "\n");
FAIL();
}
free(data);
}
int
test_main(void)
{
/* http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup */
test_salsa20(HL("80000000 00000000 00000000 00000000"),
HL("00000000 00000000"),
HL("00000000 00000000"),
H("4DFA5E48 1DA23EA0"));
test_salsa20(HL("00000000 00000000 00000000 00000000"),
HL("80000000 00000000"),
HL("00000000 00000000"),
H("B66C1E44 46DD9557"));
test_salsa20(HL("0053A6F94C9FF24598EB3E91E4378ADD"),
HL("0D74DB42A91077DE"),
HL("00000000 00000000"),
H("05E1E7BE B697D999"));
test_salsa20(HL("80000000 00000000 00000000 00000000"
"00000000 00000000 00000000 00000000"),
HL("00000000 00000000"),
HL("00000000 00000000"),
H("E3BE8FDD 8BECA2E3"));
test_salsa20(HL("00000000 00000000 00000000 00000000"
"00000000 00000000 00000000 00000000"),
HL("80000000 00000000"),
HL("00000000 00000000"),
H("2ABA3DC45B494700"));
test_salsa20(HL("0053A6F94C9FF24598EB3E91E4378ADD"
"3083D6297CCF2275C81B6EC11467BA0D"),
HL("0D74DB42A91077DE"),
HL("00000000 00000000"),
H("F5FAD53F 79F9DF58"));
SUCCESS();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment