X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavutil%2Fdes.c;h=d65760e575531e91f317dab42dc764e53289074d;hb=58c42af722cebecd86e340dc3ed9ec44b1fe4a55;hp=36f90ffaae99d83ee54330726bfa64c64dc5e9a4;hpb=2e9ad69aaf182e45e43646bda0dc89c68aecbddf;p=ffmpeg diff --git a/libavutil/des.c b/libavutil/des.c index 36f90ffaae9..d65760e5755 100644 --- a/libavutil/des.c +++ b/libavutil/des.c @@ -2,25 +2,30 @@ * DES encryption/decryption * Copyright (c) 2007 Reimar Doeffinger * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * 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. * - * FFmpeg is distributed in the hope that it will be useful, + * 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 FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include +#include "avutil.h" +#include "common.h" +#include "intreadwrite.h" #include "des.h" +typedef struct AVDES AVDES; + #define T(a, b, c, d, e, f, g, h) 64-a,64-b,64-c,64-d,64-e,64-f,64-g,64-h static const uint8_t IP_shuffle[] = { T(58, 50, 42, 34, 26, 18, 10, 2), @@ -34,6 +39,7 @@ static const uint8_t IP_shuffle[] = { }; #undef T +#if CONFIG_SMALL || defined(GENTABLES) #define T(a, b, c, d) 32-a,32-b,32-c,32-d static const uint8_t P_shuffle[] = { T(16, 7, 20, 21), @@ -46,6 +52,7 @@ static const uint8_t P_shuffle[] = { T(22, 11, 4, 25) }; #undef T +#endif #define T(a, b, c, d, e, f, g) 64-a,64-b,64-c,64-d,64-e,64-f,64-g static const uint8_t PC1_shuffle[] = { @@ -73,7 +80,7 @@ static const uint8_t PC2_shuffle[] = { }; #undef T -#ifdef CONFIG_SMALL +#if CONFIG_SMALL static const uint8_t S_boxes[8][32] = { { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18, 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87, @@ -217,7 +224,7 @@ static uint32_t f_func(uint32_t r, uint64_t k) { // apply S-boxes, those compress the data again from 8 * 6 to 8 * 4 bits for (i = 7; i >= 0; i--) { uint8_t tmp = (r ^ k) & 0x3f; -#ifdef CONFIG_SMALL +#if CONFIG_SMALL uint8_t v = S_boxes[i][tmp >> 1]; if (tmp & 1) v >>= 4; out = (out >> 4) | (v << 28); @@ -228,14 +235,14 @@ static uint32_t f_func(uint32_t r, uint64_t k) { r = (r >> 4) | (r << 28); k >>= 6; } -#ifdef CONFIG_SMALL +#if CONFIG_SMALL out = shuffle(out, P_shuffle, sizeof(P_shuffle)); #endif return out; } /** - * \brief rotate the two halves of the expanded 56 bit key each 1 bit left + * @brief rotate the two halves of the expanded 56 bit key each 1 bit left * * Note: the specification calls this "shift", so I kept it although * it is confusing. @@ -248,9 +255,8 @@ static uint64_t key_shift_left(uint64_t CDn) { return CDn; } -uint64_t ff_des_encdec(uint64_t in, uint64_t key, int decrypt) { +static void gen_roundkeys(uint64_t K[16], uint64_t key) { int i; - uint64_t K[16]; // discard parity bits from key and shuffle it into C and D parts uint64_t CDn = shuffle(key, PC1_shuffle, sizeof(PC1_shuffle)); // generate round keys @@ -260,6 +266,10 @@ uint64_t ff_des_encdec(uint64_t in, uint64_t key, int decrypt) { CDn = key_shift_left(CDn); K[i] = shuffle(CDn, PC2_shuffle, sizeof(PC2_shuffle)); } +} + +static uint64_t des_encdec(uint64_t in, uint64_t K[16], int decrypt) { + int i; // used to apply round keys in reverse order for decryption decrypt = decrypt ? 15 : 0; // shuffle irrelevant to security but to ease hardware implementations @@ -276,7 +286,60 @@ uint64_t ff_des_encdec(uint64_t in, uint64_t key, int decrypt) { return in; } +int av_des_init(AVDES *d, const uint8_t *key, int key_bits, int decrypt) { + if (key_bits != 64 && key_bits != 192) + return -1; + d->triple_des = key_bits > 64; + gen_roundkeys(d->round_keys[0], AV_RB64(key)); + if (d->triple_des) { + gen_roundkeys(d->round_keys[1], AV_RB64(key + 8)); + gen_roundkeys(d->round_keys[2], AV_RB64(key + 16)); + } + return 0; +} + +static void av_des_crypt_mac(AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt, int mac) { + uint64_t iv_val = iv ? AV_RB64(iv) : 0; + while (count-- > 0) { + uint64_t dst_val; + uint64_t src_val = src ? AV_RB64(src) : 0; + if (decrypt) { + uint64_t tmp = src_val; + if (d->triple_des) { + src_val = des_encdec(src_val, d->round_keys[2], 1); + src_val = des_encdec(src_val, d->round_keys[1], 0); + } + dst_val = des_encdec(src_val, d->round_keys[0], 1) ^ iv_val; + iv_val = iv ? tmp : 0; + } else { + dst_val = des_encdec(src_val ^ iv_val, d->round_keys[0], 0); + if (d->triple_des) { + dst_val = des_encdec(dst_val, d->round_keys[1], 1); + dst_val = des_encdec(dst_val, d->round_keys[2], 0); + } + iv_val = iv ? dst_val : 0; + } + AV_WB64(dst, dst_val); + src += 8; + if (!mac) + dst += 8; + } + if (iv) + AV_WB64(iv, iv_val); +} + +void av_des_crypt(AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) { + av_des_crypt_mac(d, dst, src, count, iv, decrypt, 0); +} + +void av_des_mac(AVDES *d, uint8_t *dst, const uint8_t *src, int count) { + av_des_crypt_mac(d, dst, src, count, (uint8_t[8]){0}, 0, 1); +} + #ifdef TEST +#undef printf +#undef rand +#undef srand #include #include #include @@ -286,25 +349,78 @@ static uint64_t rand64(void) { return r; } +static const uint8_t test_key[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; +static const DECLARE_ALIGNED(8, uint8_t, plain)[] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; +static const DECLARE_ALIGNED(8, uint8_t, crypt)[] = {0x4a, 0xb6, 0x5b, 0x3d, 0x4b, 0x06, 0x15, 0x18}; +static DECLARE_ALIGNED(8, uint8_t, tmp)[8]; +static DECLARE_ALIGNED(8, uint8_t, large_buffer)[10002][8]; +static const uint8_t cbc_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, + 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 +}; + +static int run_test(int cbc, int decrypt) { + AVDES d; + int delay = cbc && !decrypt ? 2 : 1; + uint64_t res; + AV_WB64(large_buffer[0], 0x4e6f772069732074ULL); + AV_WB64(large_buffer[1], 0x1234567890abcdefULL); + AV_WB64(tmp, 0x1234567890abcdefULL); + av_des_init(&d, cbc_key, 192, decrypt); + av_des_crypt(&d, large_buffer[delay], large_buffer[0], 10000, cbc ? tmp : NULL, decrypt); + res = AV_RB64(large_buffer[9999 + delay]); + if (cbc) { + if (decrypt) + return res == 0xc5cecf63ecec514cULL; + else + return res == 0xcb191f85d1ed8439ULL; + } else { + if (decrypt) + return res == 0x8325397644091a0aULL; + else + return res == 0xdd17e8b8b437d232ULL; + } +} + int main(void) { - int i, j; + AVDES d; + int i; +#ifdef GENTABLES + int j; +#endif struct timeval tv; - uint64_t key; + uint64_t key[3]; uint64_t data; uint64_t ct; + uint64_t roundkeys[16]; gettimeofday(&tv, NULL); srand(tv.tv_sec * 1000 * 1000 + tv.tv_usec); - key = 0x123456789abcdef0ULL; - data = 0xfedcba9876543210ULL; - if (ff_des_encdec(data, key, 0) != 0x4ab65b3d4b061518ULL) { + key[0] = AV_RB64(test_key); + data = AV_RB64(plain); + gen_roundkeys(roundkeys, key[0]); + if (des_encdec(data, roundkeys, 0) != AV_RB64(crypt)) { printf("Test 1 failed\n"); return 1; } - for (i = 0; i < 1000000; i++) { - key = rand64(); + av_des_init(&d, test_key, 64, 0); + av_des_crypt(&d, tmp, plain, 1, NULL, 0); + if (memcmp(tmp, crypt, sizeof(crypt))) { + printf("Public API decryption failed\n"); + return 1; + } + if (!run_test(0, 0) || !run_test(0, 1) || !run_test(1, 0) || !run_test(1, 1)) { + printf("Partial Monte-Carlo test failed\n"); + return 1; + } + for (i = 0; i < 1000; i++) { + key[0] = rand64(); key[1] = rand64(); key[2] = rand64(); data = rand64(); - ct = ff_des_encdec(data, key, 0); - if (ff_des_encdec(ct, key, 1) != data) { + av_des_init(&d, key, 192, 0); + av_des_crypt(&d, &ct, &data, 1, NULL, 0); + av_des_init(&d, key, 192, 1); + av_des_crypt(&d, &ct, &ct, 1, NULL, 1); + if (ct != data) { printf("Test 2 failed\n"); return 1; }