[FFmpeg-devel] [PATCH] Salsa20 algorithm

Peter Ross pross at xvid.org
Wed Jul 18 16:05:10 CEST 2012


---
The Salsa20 algorithm is necessary for a muxer/demuxer I am tinkering with.

All the current crypto algorithms within FFmpeg adhere to a quasi-standard
xxx_crypt function prototype.

Salsa20 has a seeking ability, such that one can en/decrypt a subset of the
input buffer without having to apply crypt to the earlier part of the buffer.
This is a useful feature of the algorithm that should be exposed via the API.
Ideas on how to do that welcome!

Would an 'offset' parameter be appropriate?

e.g.
void av_salsa20_crypt(struct AVSalsa20 *ctx, uint8_t *dst, const uint8_t *src, int len, const uint8_t *iv, int offset);


Cheers,

 libavutil/Makefile  |    2 +
 libavutil/salsa20.c |  169 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/salsa20.h |   45 ++++++++++++++
 3 files changed, 216 insertions(+)
 create mode 100644 libavutil/salsa20.c
 create mode 100644 libavutil/salsa20.h

diff --git a/libavutil/Makefile b/libavutil/Makefile
index ef1f658..fecc267 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -38,6 +38,7 @@ HEADERS = adler32.h                                                     \
           pixfmt.h                                                      \
           random_seed.h                                                 \
           rational.h                                                    \
+          salsa20.h                                                     \
           samplefmt.h                                                   \
           sha.h                                                         \
           time.h                                                        \
@@ -86,6 +87,7 @@ OBJS = adler32.o                                                        \
        random_seed.o                                                    \
        rational.o                                                       \
        rc4.o                                                            \
+       salsa20.o                                                        \
        samplefmt.o                                                      \
        sha.o                                                            \
        time.o                                                           \
diff --git a/libavutil/salsa20.c b/libavutil/salsa20.c
new file mode 100644
index 0000000..a6b0f4b
--- /dev/null
+++ b/libavutil/salsa20.c
@@ -0,0 +1,169 @@
+/*
+ * Salsa20 algorithm
+ * Copyright (c) 2012 Peter Ross
+ * Based on public domain implementataion by Daniel Bernstein
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "intreadwrite.h"
+#include "common.h"
+#include "salsa20.h"
+
+#if HAVE_BIGENDIAN
+#   define ROT(x, s) ((x >> s) | (x << (32-s)))
+#else
+#   define ROT(x, s) ((x << s) | (x >> (32-s)))
+#endif
+
+struct AVSalsa20 {
+    uint32_t input[16];
+};
+
+const int av_salsa20_size = sizeof(struct AVSalsa20);
+
+static void salsa20_wordtobyte(uint8_t output[64], const uint32_t input[16])
+{
+    uint32_t x[16];
+    int i;
+
+    memcpy(x, input, sizeof(x));
+
+    for (i = 12; i > 0; i -= 2) {
+        x[ 4] ^= ROT(x[ 0] + x[12],  7);
+        x[ 8] ^= ROT(x[ 4] + x[ 0],  9);
+        x[12] ^= ROT(x[ 8] + x[ 4], 13);
+        x[ 0] ^= ROT(x[12] + x[ 8], 18);
+        x[ 9] ^= ROT(x[ 5] + x[ 1],  7);
+        x[13] ^= ROT(x[ 9] + x[ 5],  9);
+        x[ 1] ^= ROT(x[13] + x[ 9], 13);
+        x[ 5] ^= ROT(x[ 1] + x[13], 18);
+        x[14] ^= ROT(x[10] + x[ 6],  7);
+        x[ 2] ^= ROT(x[14] + x[10],  9);
+        x[ 6] ^= ROT(x[ 2] + x[14], 13);
+        x[10] ^= ROT(x[ 6] + x[ 2], 18);
+        x[ 3] ^= ROT(x[15] + x[11],  7);
+        x[ 7] ^= ROT(x[ 3] + x[15],  9);
+        x[11] ^= ROT(x[ 7] + x[ 3], 13);
+        x[15] ^= ROT(x[11] + x[ 7], 18);
+        x[ 1] ^= ROT(x[ 0] + x[ 3],  7);
+        x[ 2] ^= ROT(x[ 1] + x[ 0],  9);
+        x[ 3] ^= ROT(x[ 2] + x[ 1], 13);
+        x[ 0] ^= ROT(x[ 3] + x[ 2], 18);
+        x[ 6] ^= ROT(x[ 5] + x[ 4],  7);
+        x[ 7] ^= ROT(x[ 6] + x[ 5],  9);
+        x[ 4] ^= ROT(x[ 7] + x[ 6], 13);
+        x[ 5] ^= ROT(x[ 4] + x[ 7], 18);
+        x[11] ^= ROT(x[10] + x[ 9],  7);
+        x[ 8] ^= ROT(x[11] + x[10],  9);
+        x[ 9] ^= ROT(x[ 8] + x[11], 13);
+        x[10] ^= ROT(x[ 9] + x[ 8], 18);
+        x[12] ^= ROT(x[15] + x[14],  7);
+        x[13] ^= ROT(x[12] + x[15],  9);
+        x[14] ^= ROT(x[13] + x[12], 13);
+        x[15] ^= ROT(x[14] + x[13], 18);
+    }
+
+    for (i = 0; i < 16; i++)
+        AV_WL32(output + 4 * i, x[i] + input[i]);
+}
+
+void av_salsa20_init(struct AVSalsa20 *ctx, const uint8_t *key, int key_bits)
+{
+    const char *constants;
+
+    ctx->input[1] = AV_RL32(key);
+    ctx->input[2] = AV_RL32(key + 4);
+    ctx->input[3] = AV_RL32(key + 8);
+    ctx->input[4] = AV_RL32(key + 12);
+    if (key_bits == 256) {
+        key += 16;
+        constants = "expand 32-byte k";
+    } else {
+        constants = "expand 16-byte k";
+    }
+    ctx->input[11] = AV_RL32(key);
+    ctx->input[12] = AV_RL32(key + 4);
+    ctx->input[13] = AV_RL32(key + 8);
+    ctx->input[14] = AV_RL32(key + 12);
+    ctx->input[ 0] = AV_RL32(constants);
+    ctx->input[ 5] = AV_RL32(constants + 4);
+    ctx->input[10] = AV_RL32(constants + 8);
+    ctx->input[15] = AV_RL32(constants + 12);
+}
+
+void av_salsa20_crypt(struct AVSalsa20 *ctx, uint8_t *dst, const uint8_t *src, int len, const uint8_t *iv)
+{
+    uint8_t output[64];
+    int i;
+
+    ctx->input[6] = AV_RL32(iv);
+    ctx->input[7] = AV_RL32(iv + 4);
+    ctx->input[8] = 0;
+    ctx->input[9] = 0;
+
+    while (len > 0) {
+
+        salsa20_wordtobyte(output, ctx->input);
+
+        ctx->input[8] = ctx->input[8] + 1;
+        if (!ctx->input[8])
+            ctx->input[9] = ctx->input[9] + 1;
+
+        for (i = 0; i < FFMIN(len, 64); i++)
+            dst[i] = src[i] ^ output[i];
+
+        dst += 64;
+        src += 64;
+        len -= 64;
+    }
+}
+
+#if defined(TEST)
+static const uint8_t key[32] = "thequickbrownfoxjumpsoverthelazy";
+static const uint8_t iv[8]   = "initial_";
+static const uint8_t pt[64]  = "0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
+static const uint8_t ct[64]  = {
+    0xDE,0xC4,0x40,0x7D,0x5E,0xA5,0x8A,0xF9,0x10,0x98,0x34,0xE1,0x4A,0x2A,0x62,0x04,
+    0xB5,0x49,0xA5,0x9B,0xA4,0x62,0x1B,0x56,0xF6,0x05,0x52,0x5E,0x59,0xB9,0x8B,0xB0,
+    0x4C,0xAE,0x98,0x72,0x3A,0xAB,0x17,0xA5,0x78,0x54,0x71,0xDB,0xFD,0xAA,0x6D,0xEC,
+    0x29,0xDB,0x8B,0x59,0xBC,0xA4,0xB6,0x91,0x64,0x99,0xBA,0x6E,0xEC,0x5D,0x00,0xD4,
+};
+
+int main(int argc, char **argv)
+{
+    struct AVSalsa20 ctx;
+    uint8_t tmp[64];
+
+    av_salsa20_init(&ctx, key, 256);
+
+    av_salsa20_crypt(&ctx, tmp, pt, sizeof(pt), iv);
+    if (memcmp(tmp, ct, sizeof(ct))) {
+        printf("Test encryption failed.\n");
+        return 1;
+    }
+
+    av_salsa20_crypt(&ctx, tmp, ct, sizeof(ct), iv);
+    if (memcmp(tmp, pt, sizeof(pt))) {
+        printf("Test decryption failed.\n");
+        return 1;
+    }
+
+    printf("Test encryption/decryption success.\n");
+    return 0;
+}
+#endif
diff --git a/libavutil/salsa20.h b/libavutil/salsa20.h
new file mode 100644
index 0000000..4a7b591
--- /dev/null
+++ b/libavutil/salsa20.h
@@ -0,0 +1,45 @@
+/*
+ * Salsa20 algorithm
+ * Copyright (c) 2012 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_SALSA20_H
+#define AVUTIL_SALSA20_H
+
+#include <stdint.h>
+
+extern const int av_salsa20_size;
+struct AVSalsa20;
+
+/**
+ * Initialize an AVSalsa20 context
+ * @param kbits key bits (128 or 256)
+ */
+void av_salsa20_init(struct AVSalsa20 *ctx, const uint8_t *key, int key_bits);
+
+/**
+ * Encrypt or decrypt a buffer using 12 round cipher and previously initialized context.
+ * @param dst destination buffer, can be equal to src
+ * @param src source buffer, can be equal to dst
+ * @param len buffer length (bytes)
+ * @param iv initialization vector (8 bytes)
+ */
+void av_salsa20_crypt(struct AVSalsa20 *ctx, uint8_t *dst, const uint8_t *src, int len, const uint8_t *iv);
+
+#endif /* AVUTIL_SALSA20_H */
-- 
1.7.10.4

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120719/10ba86e5/attachment.asc>


More information about the ffmpeg-devel mailing list