On Sat, Jun 30, 2012 at 03:22:16PM +0200, Samuel Pitoiset wrote:
> ---
> libavutil/Makefile | 1 +
> libavutil/bf.c | 410
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
> libavutil/bf.h | 59 ++++++++
> 3 files changed, 470 insertions(+), 0 deletions(-)
> create mode 100644 libavutil/bf.c
> create mode 100644 libavutil/bf.h
nit: more meaningful filename would be better (what's wrong with
blowfish.[ch]?)
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 6fe174b..b1f7183 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -51,6 +51,7 @@ OBJS = adler32.o
> \
> audioconvert.o \
> avstring.o \
> base64.o \
> + bf.o \
> cpu.o \
> crc.o \
> des.o \
> diff --git a/libavutil/bf.c b/libavutil/bf.c
> new file mode 100644
> index 0000000..afaeeae
> --- /dev/null
> +++ b/libavutil/bf.c
> @@ -0,0 +1,410 @@
> +/*
> + * Blowfish algorithm
> + * Copyright (c) 2012 Samuel Pitoiset
> + *
> + * loosely based on Paul Kocher's implementation
> + *
> + * This file is part of Libav.
> + *
> + * Libav 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.
> + *
> + * Libav 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 Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA
> + */
> +
> +#include "avutil.h"
> +#include "common.h"
> +#include "bf.h"
> +
> +typedef struct AVBF AVBF;
I think it would be better to declare
typedef struct AVBlowfish {
...
} AVBlowfish;
in the header. And the name should be more meaningful.
Same for other 'av_bf_*' names.
> +static const uint32_t orig_p[BF_ROUNDS + 2] = {
> + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
> + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
> + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
> + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
> + 0x9216D5D9L, 0x8979FB1BL
> +};
'L' suffixes are not needed ('U' would be more appropriate here.
> +
> +static const uint32_t orig_s[4][256] = {
> + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L,
nit: formatting like
static const uint32_t orig_s[4][256] = {
{
0xB8E1AFEDu, 0x6A267E96u, 0xBA7C9045u, 0xF12C7F99u,
...
},
{
...
}
};
would look better (but Diego might suggest even better formatting)
[...]
> +static uint32_t F(AVBF *bf, uint32_t x)
> +{
> + uint16_t a, b, c, d;
> + uint32_t y;
> +
> + d = (uint16_t)(x & 0xFF);
> + x >>= 8;
> + c = (uint16_t)(x & 0xFF);
> + x >>= 8;
> + b = (uint16_t)(x & 0xFF);
> + x >>= 8;
> + a = (uint16_t)(x & 0xFF);
> + y = bf->s[0][a] + bf->s[1][b];
> + y = y ^ bf->s[2][c];
> + y = y + bf->s[3][d];
this can be simplified by eliminating temporary variables:
y = bf->s[0][(x >> 24) & 0xFF];
y += bf->s[1][(x >> 16) & 0xFF];
y ^= bf->s[2][(x >> 8) & 0xFF];
y += bf->s[3][ x & 0xFF];
> + return y;
> +}
> +
> +void av_bf_init(AVBF *bf, const uint8_t *key, int key_len)
> +{
> + uint32_t data, datal, datar;
> + int i, j, k;
> +
> + for (i = 0; i < 4; i++) {
> + for (j = 0; j < 256; j++)
> + bf->s[i][j] = orig_s[i][j];
> + }
memcpy(bf->s, orig_s, sizeof(orig_s)) ?
> + j = 0;
> + for (i = 0; i < BF_ROUNDS + 2; ++i) {
> + data = 0x00000000;
> + for (k = 0; k < 4; ++k) {
make it k++ for consistency
> + data = (data << 8) | key[j];
> + j = j + 1;
I'd suggest data = (data << 8) | key[j++];
> + if (j >= key_len)
> + j = 0;
> + }
> + bf->p[i] = orig_p[i] ^ data;
> + }
> +
> + datal = 0x00000000;
> + datar = 0x00000000;
> +
> + for (i = 0; i < BF_ROUNDS + 2; i += 2) {
> + av_bf_encrypt(bf, &datal, &datar);
> + bf->p[i] = datal;
> + bf->p[i + 1] = datar;
> + }
> +
> + for (i = 0; i < 4; ++i) {
> + for (j = 0; j < 256; j += 2) {
> + av_bf_encrypt(bf, &datal, &datar);
> + bf->s[i][j] = datal;
> + bf->s[i][j + 1] = datar;
> + }
> + }
> +}
> +
> +void av_bf_encrypt(AVBF *bf, uint32_t *xl, uint32_t *xr)
> +{
> + uint32_t Xl, Xr, tmp;
> + int i;
> +
> + Xl = *xl;
> + Xr = *xr;
> +
> + for (i = 0; i < BF_ROUNDS; ++i) {
> + Xl = Xl ^ bf->p[i];
> + Xr = F(bf, Xl) ^ Xr;
make it uniform:
1)
Xl = Xl ^ bf->p[i];
Xr = Xr ^ F(bf, Xl);
or 2)
Xl ^= bf->p[i];
Xr ^= F(bf, Xl);
> +
> + tmp = Xl;
> + Xl = Xr;
> + Xr = tmp;
FFSWAP(uint32_t, Xl, Xr);
> + }
> +
> + tmp = Xl;
> + Xl = Xr;
> + Xr = tmp;
here too
> +
> + Xr = Xr ^ bf->p[BF_ROUNDS];
> + Xl = Xl ^ bf->p[BF_ROUNDS + 1];
> +
> + *xl = Xl;
> + *xr = Xr;
> +}
> +
> +void av_bf_decrypt(AVBF *bf, uint32_t *xl, uint32_t *xr)
> +{
> + uint32_t Xl, Xr, tmp;
> + int i;
> +
> + Xl = *xl;
> + Xr = *xr;
> +
> + for (i = BF_ROUNDS + 1; i > 1; --i) {
> + Xl = Xl ^ bf->p[i];
> + Xr = F(bf, Xl) ^ Xr;
> +
> + tmp = Xl;
> + Xl = Xr;
> + Xr = tmp;
> + }
> +
> + tmp = Xl;
> + Xl = Xr;
> + Xr = tmp;
> +
> + Xr = Xr ^ bf->p[1];
> + Xl = Xl ^ bf->p[0];
> +
> + *xl = Xl;
> + *xr = Xr;
> +}
Looks like crypt() and decrypt() differ only by direction of rounds applied,
maybe you should factor out it and have simply:
static void blowfish_crypt(AVBlowfish *bf, uint32_t *xl, uint32_t *xr,
int direction)
{
...
}
void av_blowfish_decrypt(AVBlowfish *bf, uint32_t *xl, uint32_t *xr)
{
blowfish_crypt(bf, xl, xr, 1);
}
> diff --git a/libavutil/bf.h b/libavutil/bf.h
> new file mode 100644
> index 0000000..a4cba13
> --- /dev/null
> +++ b/libavutil/bf.h
> @@ -0,0 +1,59 @@
> +/*
> + * Blowfish algorithm
> + *
> + * This file is part of Libav.
> + *
> + * Libav 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.
> + *
> + * Libav 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 Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA
> + */
> +
> +#ifndef AVUTIL_BF_H
> +#define AVUTIL_BF_H
> +
> +#include <stdint.h>
> +
> +#define BF_ROUNDS 16
> +
> +struct AVBF {
> + uint32_t p[BF_ROUNDS + 2];
> + uint32_t s[4][256];
> +};
> +
> +/**
> + * @brief Initializes an AVBF context.
> + *
> + * @param key a key
> + * @param key_len length of the key
all parameters should be documented
> + */
> +void av_bf_init(struct AVBF *bf, const uint8_t *key, int key_len);
> +
> +/**
> + * @brief Encrypts using the Blowfish algorithm.
> + *
> + * @param bf an AVBF context
> + * @param xl TODO : what is the good description here?
> + * @param xr TODO
Those are supposed to be eight bytes of input that should be encrypted.
And you're supposed to use it _knowingly_ ;)
Feel free to have a look at C++ implementation -
http://www.schneier.com/code/bfsh-con.zip
It has wrapper that shows how to use that on real input/output.
> + */
> +void av_bf_encrypt(struct AVBF *bf, uint32_t *xl, uint32_t *xr);
> +
> +/**
> + * @brief Decrypts using the Blowfish algorithm.
> + *
> + * @param bf an AVBF context
> + * @param xl TODO
> + * @param xr TODO
> + */
> +void av_bf_decrypt(struct AVBF *bf, uint32_t *xl, uint32_t *xr);
> +
> +#endif /* AVUTIL_BF_H */
> --
Also there's self-test program missing. Look at libavutil/sha.c for an example
of one, I'm sure Diego will help with Makefile part for it.
Test vectors are available at http://www.schneier.com/code/vectors2.txt
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel