log: Remove redundant va_list creation from missing_feature_sample()
[ffmpeg.git] / libavutil / des.c
index 51d73a3..a7a5074 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include <inttypes.h>
+#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),
@@ -35,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),
@@ -47,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[] = {
@@ -236,7 +242,7 @@ static uint32_t f_func(uint32_t r, uint64_t k) {
 }
 
 /**
- * \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.
@@ -249,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
@@ -261,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
@@ -277,38 +286,136 @@ 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, av_unused 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 <stdlib.h>
 #include <stdio.h>
-#include <sys/time.h>
+#include "libavutil/time.h"
 static uint64_t rand64(void) {
     uint64_t r = rand();
     r = (r << 32) | rand();
     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;
-    struct timeval tv;
-    uint64_t key;
+    AVDES d;
+    int i;
+#ifdef GENTABLES
+    int j;
+#endif
+    uint64_t key[3];
     uint64_t data;
     uint64_t ct;
-    gettimeofday(&tv, NULL);
-    srand(tv.tv_sec * 1000 * 1000 + tv.tv_usec);
-    key = 0x123456789abcdef0ULL;
-    data = 0xfedcba9876543210ULL;
-    if (ff_des_encdec(data, key, 0) != 0x4ab65b3d4b061518ULL) {
+    uint64_t roundkeys[16];
+    srand(av_gettime());
+    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, (uint8_t*)key, 192, 0);
+        av_des_crypt(&d, (uint8_t*)&ct, (uint8_t*)&data, 1, NULL, 0);
+        av_des_init(&d, (uint8_t*)key, 192, 1);
+        av_des_crypt(&d, (uint8_t*)&ct, (uint8_t*)&ct, 1, NULL, 1);
+        if (ct != data) {
             printf("Test 2 failed\n");
             return 1;
         }