2015-08-14 4 views
1

У меня есть поток байтов, который возвращает последовательность байтовых массивов, каждая из которых представляет собой одну запись.Лучший разделитель для безопасного анализа байтовых массивов из потока

Я хотел бы проанализировать поток в списке отдельных байт [] s. В настоящее время я взломал трехбайтовый разделитель, чтобы я мог идентифицировать конец каждой записи, но у вас есть проблемы.

Я вижу, что существует стандартный разделитель символов Ascii.

30 036 1E 00011110 RS   Record Separator 

ли безопасно использовать байты [], производные от этого символа, если разделитель были сжаты массивы байт (которые были UTF-8, кодируемые) и/или зашифрованы? Меня беспокоит то, что выход шифрования/сжатия может создать разделитель записи для какой-либо другой цели. Обратите внимание, что отдельные байтовые [] записи сжаты/зашифрованы, а не весь поток.

Я работаю на Java 8 и используя Snappy для сжатия. Я еще не выбрал библиотеку шифрования, но это, безусловно, будет одним из более сильных, стандартных, частных ключей.

+0

Частные ключевые подходы не являются более сильными. Они просто используются для разных приложений, в основном для ключевых соглашений или для транспортировки ключей. Вы должны кодировать длину каждого сообщения в потоке, а не пытаться выбрать разделитель. Это безопаснее и проще. – erickson

+0

@erickson Я думаю, вы пропустили запятую между более сильным и закрытым ключом. Я говорил о стандартных алгоритмах секретного ключа, я бы выбрал один из самых сильных. Кроме того, вы запутываете секретный и открытый ключ. Ключ открытого ключа используется для согласования и для передачи частных (симметричных) ключей. –

+0

Хорошо, хотелось убедиться, что вы не работали под общим заблуждением, что асимметричные алгоритмы более безопасны, чем симметричные алгоритмы. «Симметричный» или «секретный ключ» гораздо менее правдоподобен, чем «закрытый ключ». – erickson

ответ

1

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

Если у вас есть длина, вам не нужен разделитель. Ваша сторона чтения читает длину, затем знает, сколько нужно прочитать для первой записи, а затем знает, как читать следующую длину - все предполагают, что сами длины являются фиксированными.

См. the developers' suggestions for streaming a sequence of protobufs.

+0

Как это происходит, они являются protobufs (игнорируя сжатие/шифрование), но поток протобуфов, а не один protobuf. Существует ли стандартный способ, чтобы поток отдельных протобуфов был бы ограничен? Кроме того, учитывая предложенную схему длины записи, разве мне не нужно будет идентифицировать начало каждой записи? Не уверен, как это помогает. –

4

Вы не можете просто объявить байт в качестве разделителя, если работаете со случайными неструктурированными данными (которые сжатые/зашифрованные данные похожи довольно близко), поскольку разделитель всегда может отображаться как обычный байт данных в таких данных.

Если размер данных уже известен, когда вы начинаете писать, просто напишите сначала размер, а затем данные. При чтении вы тогда знаете, вам нужно сначала прочитать размер (например, 4 байта для int), а затем указать столько байтов, сколько указано.

Это, очевидно, не работает, если вы не можете указать размер при записи. В этом случае вы можете использовать механизм экранирования, например. выберите редко появляющийся байт в качестве символа escapce, избегайте всех событий этого байта в данных и используйте другой байт в качестве индикатора конца.

например.

final static byte ESCAPE = (byte) 0xBC; 
final static byte EOF = (byte) 0x00; 

OutputStream out = ... 
for (byte b : source) { 
    if (b == ESCAPE) { 
     // escape data bytes that have the value of ESCAPE 
     out.write(ESCAPE); 
     out.write(ESCAPE); 
    } else { 
     out.write(b); 
    } 
} 
// write EOF marker ESCAPE, EOF 
out.write(ESCAPE); 
out.write(EOF); 

Теперь при чтении и вы читаете ESCAPE байт, вы читали рять ж следующий байт и проверить EOF. Если его не EOF, это escape-код ESCAPE, который представляет собой байт данных.

InputStream in = ... 
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
while ((int b = in.read()) != -1) { 
    if (b == ESCAPE) { 
     b = in.read(); 
     if (b == EOF) 
      break; 
     buffer.write(b); 
    } else { 
     buffer.write(b); 
    } 
} 

Если байты должны быть записаны отлично распределены случайным образом это увеличит длину потока по 1/256, для областей данных, которые не являются полностью случайными, вы можете выбрать байты, который не менее часто появляющиеся (статическим анализ данных или просто образованное предположение).

Редактирование: вы можете уменьшить накладные расходы, используя более сложную логику, например. пример может создать только ESCAPE + ESCAPE или ESCAPE + EOF.Другие 254 байта никогда не могут следовать за ESCAPE в этом примере, поэтому их можно было бы использовать для хранения легальных комбинаций данных.

+0

Вместо того, чтобы ускользать, большинство протоколов, которые поддерживают сообщения, где длина не известна заранее, используют подход chunking, где каждый фрагмент кодируется по длине, а затем последний фрагмент имеет длину нуля, чтобы сигнализировать о конце сообщения. – erickson

 Смежные вопросы

  • Нет связанных вопросов^_^