konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Witam,

Piszę program, który przesyła pliki w blokach o dowolnej (ustalanej w pliku konfiguracyjnym) wielkości.
W skrócie: serwer wczytuje do tablicy bajtów (o rozmiarze bloku) fragment pliku i wysyła, aż plik się skończy. Klient odbiera ten blok danych i zapisuje do pliku.

Dla każdego wysłanego bloku obliczam skrót MD5 i przesyłam go do klienta, aby mógł porównać ze swoim skrótem obliczonym z odebranego bloku.

I tutaj problem: blok którego wielkość ustalam sobie na serwerze nie zawsze dociera do klienta w całośći, tylko w mniejszych porcjach (tną go chyba sockety gdy dane nie zmieszczą się w ich buforze?).
I wtedy liczenie md5 dla odebranego bloku nie ma sensu, bo jest liczone z innej porcji danych.

Próbowałem wymyślić jakąś metodę, która będzie obliczać skrót dopiero po spełnieniu odpowiedniego warunku, ale niestety bez skótku.

Czy ma ktoś z Was pomysł jak rozwiązać ten problem?

PozdrawiamTomasz Sobczak edytował(a) ten post dnia 28.03.10 o godzinie 10:35

konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Może coś w stylu (piszę bez edytora, to tylko koncepcja)

class ReceiveBuffer {

byte[] buffer;
int size;
int curIndex;

byte[] md5Checksum;

public ReceiveBuffer(int size) {
buffer = new byte[size];
this.size = size;
}

public void appendToBuffer(byte[] received) {
curIndex += received.length;
if (curIndex>size) {
System.arrayCopy(z received do bufora)
// wszystko co chcesz zrobic po stwierdzeniu, ze pakiet jest ok
checkMd5Checksum(buffer, md5checksum);
buffer = new byte[size];
System.arrayCopy(pozostale z received do bufora)
} else {
System.arrayCopy(calosc do bufora)
}
}

}

konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Dziękuje za podpowiedź, jutro to przeanalizuję i dam znać, czy mi coś wyszło :)

konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Witam,

Przeanalizowałem Twój kod i rozumiem, że ma to działać mniej więcej tak:
metoda appendToBuffer pobiera bloki danych i jeśli ich łączna długość przekroczy właściwą długość bloku (int size) to jest obliczane MD5 z danych dodawanych do bufora. Dane są zapisywane w buforze jeśli curIndex jest mniejszy od właściwej długości bloku.

Na podstawie tego napisałem:

public class MD5 {

public MD5(int size) {
this.buffer = new byte[size];
this.blockSize = size;
}

//readBytes to liczba która określa ilosc odebranych bajtów
//dataBlock.length jest zawsze takie samo, a liczba odebranych z
//socketa bajtów jest różna
//tzn: readBytes = input.read(fileBytes, 0, fileBytes.length);

public void check(byte[] dataBlock, int readBytes) {
this.curIndex += readBytes;

if (this.curIndex > this.blockSize) {
String md5 = calcMD5(this.buffer);

this.buffer = new byte[this.blockSize];

//po obliczeniu md5 curIndex rowna sie juz
//tylko dlugosci ostatnio odebranego bloku
this.curIndex = readBytes;

//zerowanie zmiennej ktora wskazuje od ktorego
//momentu zapisywac dane w buforze
this.rememberPos = 0;

appendToBuffer(dataBlock, readBytes);
}
else {
appendToBuffer(dataBlock, readBytes);
}
}

private void appendToBuffer(byte[] dataBlock, int readBytes) {
//metoda ktora dodaje bloki danych do bufora
//zmienna rememberPos na poczatku rowna sie zero
//a potem dlugosci wczytanego bloku.
//dzieki temu dane w buforze nie sa nadpisywane
System.arraycopy(dataBlock, 0, this.buffer, this.rememberPos, readBytes);
this.rememberPos = readBytes;
}

private String calcMD5(byte[] blokDanych) {
//obliczanie skrotu MD5
String skrotMD5 = null;

try {
MessageDigest digest = MessageDigest.getInstance("MD5");

if (blokDanych.length > 0)
digest.update(blokDanych, 0, blokDanych.length);

byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
skrotMD5 = bigInt.toString(16);
}
catch(NoSuchAlgorithmException ex) {
ex.printStackTrace();
}

return skrotMD5;
}

private byte[] buffer;
private int blockSize,
curIndex,
count = 0,
rememberPos = 0;
}


Niestety w większości przypadków to rozwiązanie nie działa, tzn skróty MD5 (oryginalne i bloków przesłanych) są różne...Tomasz Sobczak edytował(a) ten post dnia 29.03.10 o godzinie 15:38

konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Twoja klasa jest zaimplementowana niepoprawnie. Nie powiem Ci gdzie jest błąd, sam popracuj. Poniżej test (mam nadzieję, że poprawny), który pomoże ci w badaniu problemu.

package md5;

import java.util.Arrays;
import java.util.Random;

import junit.framework.Assert;
import junit.framework.TestCase;

import org.junit.Test;

public class MD5Test extends TestCase {

byte[] dataToSend;
MD5 md5;
int blockSize = 4096;
Random gen;
@Override
protected void setUp() throws Exception {
md5 = new MD5(blockSize);
gen = new Random();
dataToSend = new byte[65536];
gen.nextBytes(dataToSend);
}

@Override
protected void tearDown() throws Exception {
super.tearDown();
}

@Test
public void testCheck() {
int index = 0;
int nextSize = gen.nextInt(1000)+1000;
if (nextSize>blockSize) {
nextSize = blockSize;
}
byte[] curBytes = null;
do {
// twoje md5
curBytes = new byte[nextSize+gen.nextInt(200)];
System.arraycopy(dataToSend, index, curBytes, 0, nextSize);
String md5checksum = md5.check(curBytes, nextSize);
if (md5checksum!=null) {
// nasze md5
curBytes = new byte[blockSize];
System.arraycopy(dataToSend, (index/blockSize)*blockSize, curBytes, 0, curBytes.length);
String md5_expected = MD5.calcMD5(curBytes);
System.out.println(Arrays.toString(md5.prevBuffer));
System.out.println(Arrays.toString(curBytes));
Assert.assertEquals(md5.prevBuffer.length, curBytes.length);
Assert.assertTrue(Arrays.equals(md5.prevBuffer, curBytes));
Assert.assertEquals(md5_expected, md5checksum);
}
index+=nextSize;
nextSize = gen.nextInt(1000)+1000;
} while (index+nextSize<dataToSend.length);
}

}


Poniżej lekko zmodyfikowana wersja twojej klasy


package md5;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5 {


byte[] buffer;
byte[] prevBuffer;
int blockSize,
curIndex,
count = 0,
rememberPos = 0;
public MD5(int size) {
this.buffer = new byte[size];
this.blockSize = size;
}

// readBytes to liczba która określa ilosc odebranych bajtów
// dataBlock.length jest zawsze takie samo, a liczba odebranych z
// socketa bajtów jest różna
// tzn: readBytes = input.read(fileBytes, 0, fileBytes.length);

public String check(byte[] dataBlock, int readBytes) {
this.curIndex += readBytes;
if (this.curIndex > this.blockSize) {
String md5 = calcMD5(this.buffer);
prevBuffer = buffer;
this.buffer = new byte[this.blockSize];
// po obliczeniu md5 curIndex rowna sie juz
// tylko dlugosci ostatnio odebranego bloku
this.curIndex = readBytes;

// zerowanie zmiennej ktora wskazuje od ktorego
// momentu zapisywac dane w buforze
this.rememberPos = 0;
appendToBuffer(dataBlock, readBytes);
return md5;

} else {
appendToBuffer(dataBlock, readBytes);
}
return null;

}

private void appendToBuffer(byte[] dataBlock, int readBytes) {

// metoda ktora dodaje bloki danych do bufora
// zmienna rememberPos na poczatku rowna sie zero
// a potem dlugosci wczytanego bloku.
// dzieki temu dane w buforze nie sa nadpisywane

System.arraycopy(dataBlock, 0, this.buffer, this.rememberPos, readBytes);
this.rememberPos = readBytes;
}

public static String calcMD5(byte[] blokDanych) {
// obliczanie skrotu MD5
String skrotMD5 = null;
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
if (blokDanych.length > 0){
digest.update(blokDanych, 0, blokDanych.length); }
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
skrotMD5 = bigInt.toString(16);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
return skrotMD5;
}

}
Dariusz Wawer edytował(a) ten post dnia 30.03.10 o godzinie 10:19

konto usunięte

Temat: Obliczanie MD5 dla przesyłanych bloków danych

Na wstępie dziękuje za kod testu,

Wydaje mi się, że znalazłem błąd:

private void appendToBuffer(byte[] dataBlock, int readBytes) {
System.arraycopy(dataBlock, 0, this.buffer, this.rememberPos, readBytes);

//do rememberPos powinienem zapisywać zmienną curIndex, a nie readBytes - źle dobieram początek zapisywania danych w buforze
this.rememberPos = this.curIndex;
}
Tomasz Sobczak edytował(a) ten post dnia 30.03.10 o godzinie 22:18

Następna dyskusja:

Ciekawe projekty dla ludzi ...




Wyślij zaproszenie do