Ошибка 128-битного типа - PullRequest
       8

Ошибка 128-битного типа

0 голосов
/ 01 ноября 2009

Благодаря справке pbos и ее программе (опубликованной здесь , для сохранения большого файла) я провел несколько тестов и вижу, что у меня есть еще одна проблема: изменив маску другой из 128- немного, по умолчанию нет такого большого типа, как нужно.

Я думаю, что решением может быть включение библиотеки для увеличения доступных целочисленных типов ... но я предпочитаю интерпретировать каждые 128-битные значения, такие как строки. Это возможно без потери производительности?

Вот текущая программа (с ошибкой «целочисленная константа слишком велика для своего типа»):

#include <stdio.h>
#include <stdlib.h>

#define BLOCKSIZE 128
#define MASK 0xA37c54f173f02889a64be02f2bc44112 /* a 128 bits constant */

void
usage(const char *cmd)
{
    fprintf(stderr, "Usage: %s <in-file> [<out-file>]\n", cmd);
    exit (EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
  if (argc < 3) usage(argv[0]);

  FILE *in = fopen(argv[1], "rb");

  if (in == NULL)
  {
    printf("Cannot open: %s", argv[2]);
    return EXIT_FAILURE;
  }

  FILE *out = fopen(argv[2], "wb");

  if (out == NULL)
  {
    fclose(in);
    printf("Unable to open '%s' for writing.", argv[2]);
  }

  char buffer[BLOCKSIZE];
  int count;

  while (count = fread(buffer, 1, BLOCKSIZE, in))
  {
    int i;
    for (i = 0; i < count; i++)
    {
      ((unsigned long *)buffer)[i] ^= MASK; /* this line is bugged */
    }

    if (fwrite(buffer, 1, count, out) != count)
    {
      fclose(in);
      fclose(out);
      printf("Cannot write, disk full?\n");
      return EXIT_FAILURE;
    }
  }

  fclose(in);
  fclose(out);

  return EXIT_SUCCESS;
}

Спасибо за любые предложения.

Doug

Ответы [ 6 ]

2 голосов
/ 01 ноября 2009

Пройдите по байтному ключу и открытому тексту и выполните XOR для каждого байта отдельно.

Измените ваш ключ на массив байтов и создайте указатель на этот массив для удобства использования ключа:

char const key[] = {
    0xA3, 0x7c, 0x54, 0xf1, 
    0x73, 0xf0, 0x28, 0x89, 
    0xa6, 0x4b, 0xe0, 0x2f, 
    0x2b, 0xc4, 0x41, 0x12
};

char const* pKeyByte = key;

Затем измените строку, с которой вы шифруете, с

((unsigned long *)buffer)[i] ^= MASK; /* this line is bugged */

до:

buffer[i] ^= *pKeyByte++;
if (pKeyByte == (key + sizeof(key))) {
    /* wrap to start of key */
    pKeyByte = key;
}

Теперь вы можете изменить BLOCKSIZE на любой желаемый размер ввода / вывода независимо от длины ключа. Обратите внимание, что, поскольку вы используете его, BLOCKSIZE определяет количество байтов, которые будут считываться из файла в каждом цикле - это не количество бит в ключе.

Обратите внимание, что предостережения о шифровании XOR , которые я опубликовал в вашем последнем вопросе, все еще применяются.

2 голосов
/ 01 ноября 2009

Маскируйте четные «куски» первой половиной вашей постоянной и нечетные «куски» другой половиной.

/* ... */
unsigned int xormask[2] = {0xA37c54f173f02889, 0xa64be02f2bc44112};
/* ... */
        for(i = 0;i < end; ++i)
        {
                ((unsigned int *)buffer)[i] ^= xormask[i & 1];
        }
/* ... */
1 голос
/ 01 ноября 2009

Не все (многие?) Платформы будут поддерживать 128-битные целые числа. Вы можете выделить код, который имеет непосредственное отношение к 128-битным числам, и написать две его версии: одну для платформ, поддерживающих 128-битные числа, и другую для тех, которые этого не делают. Сценарий конфигурации может проверять 128-битную поддержку (отметьте «sizeof(long long)» и «uint128_t», возможно?) И выбрать между двумя реализациями.

0 голосов
/ 01 ноября 2009

Размеры целочисленных типов являются основной характеристикой языка. Его нельзя изменить, включив какие-либо библиотеки. Если вы настаиваете на использовании встроенных целочисленных типов, единственный способ преодолеть это ограничение - перейти на другую реализацию, которая изначально поддерживает большие целочисленные типы на уровне основного языка.

В противном случае вам придется либо явно разделить вашу «длинную» константу на две или более «более короткие» константы, либо использовать некоторую библиотеку, которая будет делать то же самое «под капотом».

0 голосов
/ 01 ноября 2009

Основываясь на ответе Burr , я бы предпочел следующее:

int i;
int sizeOfKey = sizeof(key); // key is an array of chars
for (i = 0; i < count; i++)
{
    buffer[i] ^= key[i % sizeOfKey];
}

Наличие внутреннего цикла предполагает, что выровнен по 16 байтов (т.е. buffer[i + j] не проверяет фактическую длину буфера).

0 голосов
/ 01 ноября 2009

Вам также понадобится разбить маску на куски.

unsigned int mask[] = { 0xA37c54f1, 0x73f02889, 0xa64be02f, 0x2bc44112 };
unsigned int mask_len = sizeof(mask) / sizeof(*mask);

Затем вам нужно будет работать с буфером, в котором вы читаете, как с серией unsigned int, а не с символами и xor для фрагмента с соответствующим фрагментом маски:

unsigned int *uint_buffer = (unsigned int *)buffer;
for (i = 0; i < count / sizeof(int); i++)
{
    uint_buffer[i] ^= mask[i % mask_len];
}

Наконец, в зависимости от специфики вашей задачи вам может потребоваться решить проблемы с порядком байтов в данных, которые вы читаете из файла.

...