2010-03-02 4 views
3

Мне нужно зашифровать и отправить данные через TCP (от нескольких 100 байт до нескольких 100 мегабайт на сообщение) в кусках от Java до C++-программы и необходимо заранее отправить размер данных, чтобы получатель знает, когда прекратить чтение текущего сообщения и обработать его, а затем ждать следующего сообщения (соединение остается открытым, поэтому нет другого способа указать конец сообщения, так как данные могут быть двоичными, я не могу использовать флаг для указать конец сообщения из-за возможности того, что зашифрованные байты могут случайно оказаться идентичными любому выбранному флагу в какой-либо точке).getOutputSize постоянство?

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

Скажем, я инициализируется следующим образом:

AlgorithmParameterSpec paramSpec = new IvParameterSpec(initv); 
encipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
mac = Mac.getInstance("HmacSHA512"); 
encipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 
mac.init(key); 
buf = new byte[encipher.getOutputSize(blockSize)]; 

Тогда Я отправить данные, такие, как (а также имеют аналогичную функцию, которая использует поток для ввода вместо byte[]):

public void writeBytes(DataOutputStream out, byte[] input) { 
try { 
    //mac.reset(); // Needed ? 
    int left = input.length; 
    int offset = 0; 
    while (left > 0) 
    { 
    int chunk = Math.min(left, blockSize); 
    int ctLength = encipher.update(input, offset, chunk, buf, 0); 
    mac.update(input, offset, chunk); 
    out.write(buf, 0, ctLength); 
    left -= chunk; 
    offset += chunk; 
    } 
    out.write(encipher.doFinal(mac.doFinal()); 
    out.flush(); 
} catch (Exception e) { 
    e.printStackTrace(); 
} 
} 

Но как предусмотреть размер вывода, который будет отправлен на принимающий компьютер? В принципе, я хочу out.writeInt (messageSize) перед циклом. Но как вычислить messageSize? В документации для Cipher's getOutputSize() говорится, что «этот вызов учитывает любые необработанные (буферизованные) данные из предыдущего вызова обновления и отступы». Таким образом, это, по-видимому, означает, что значение может измениться для одного аргумента функции по нескольким вызовам до update() или doFinal() ... Могу ли я предположить, что если blockSize является кратным размеру блока AES CBC, чтобы избежать заполнения, я должен иметь постоянное значение для каждого блока? То есть, просто проверить, что _blockSize % encipher.getOutputSize(1) != 0, а затем в функции записи,

int messageSize = (input.length/blockSize) * encipher.getOutputSize(blockSize) +      
        encipher.getOutputSize(input.length % blockSize + mac.getMacLength()); 

??

Если нет, то какие у меня альтернативы?

+1

Ваше угадывание, исправление, молитва. Используйте SSL/TLS. Java JSSE имеет простую в использовании поддержку SSL. –

+0

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

ответ

1

При использовании PKCS5 отступов, размер сообщения после заполнения будет:

padded_size = original_size + BLOCKSIZE - (original_size % BLOCKSIZE); 

выше дает полный размер всего сообщения (вплоть до doFinal() вызова), учитывая полный размер входного сообщения. Мне приходит в голову, что вы действительно хотите знать длину последней части - все, что вам нужно сделать, это сохранить выходной байтовый массив вызова doFinal() и использовать метод .length() для этого массива.

+0

Привет, кафе, я полагаю, что BLOCKSIZE - это то, что Cipher.getBlocksize() возвращается? Спасибо – Prune

+0

Да (это должно быть 16 для AES). – caf

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