2013-05-16 32 views
10

Ponieważ tryb AES w trybie CTR doskonale nadaje się do dostępu losowego, powiedzmy, że mam źródło danych utworzone w trybie AES-CTR z CipherOutputStream. Biblioteka pod spodem, która nie jest moja, używa wartości RandomAccessFile, która umożliwia wyszukiwanie określonego przesunięcia bajtu w pliku.Szukanie zaszyfrowanego wejścia AES-CTR

Moją pierwszą myślą byłoby użyć CipherInputStream z Cipher inicjowane z odpowiednimi parametrami, ale the API for that nie robi poszukiwania i stwierdza, aby nie obsługiwać mark i reset.

Czy istnieje część interfejsu API, którą przeoczyłem, która może zrobić to dla mnie, powinienem zajrzeć do konfiguracji licznika IV/bloku CTR i odtworzyć go za pomocą niestandardowego strumienia wejściowego (który brzmi jak strzelba mająca na celu self) lub zastosować inne podejście, które przegapiłem?

Odpowiedz

9

Prawo, zauważyłem właśnie dostałem odznakę Tumbleweed do tego, „yay” ...

skończyło się patrząc jak dokładnie IV jest aktualizowana w trybie CTR. Okazuje się, że robi to proste +1 dla każdego bloku AES, który przetwarza. Zaimplementowałem czytanie wzdłuż następujących linii.

Biorąc klasa, która implementuje read -jak metodę, która będzie czytać następny bajt w sekwencji bajtów, które są kodowane i musi wspierać poszukiwanie w tej kolejności i następujące zmienne:

  • BLOCK_SIZE: ustalona na 16 (128 bitów, rozmiar bloku AES);
  • cipher: instancja javax.crypto.Cipher, zainicjowana w celu obsługi AES;
  • delegate: a java.io.InputStream, który opakowuje zaszyfrowany zasób, który umożliwia dostęp losowy;
  • input: a javax.crypto.CipherInputStream będziemy serwować odczyty (strumień zajmie się odszyfrowaniem).

Sposób seek jest realizowany w następujący sposób:

void seek(long pos) { 
    // calculate the block number that contains the byte we need to seek to 
    long block = pos/BLOCK_SIZE; 
    // allocate a 16-byte buffer 
    ByteBuffer buffer = ByteBuffer.allocate(BLOCK_SIZE); 
    // fill the first 12 bytes with the original IV (the iv minus the actual counter value) 
    buffer.put(cipher.getIV(), 0, BLOCK_SIZE - 4); 
    // set the counter of the IV to the calculated block index + 1 (counter starts at 1) 
    buffer.putInt(block + 1); 
    IvParameterSpec iv = new IvParameterSpec(buffer.array()); 
    // re-init the Cipher instance with the new IV 
    cipher.init(Cipher.ENCRYPT_MODE, key, iv); 
    // seek the delegate wrapper (like seek() in a RandomAccessFile and 
    // recreate the delegate stream to read from the new location) 
    // recreate the input stream we're serving reads from 
    input = new CipherInputStream(delegate, cipher); 
    // next read will be at the block boundary, need to skip some bytes to arrive at pos 
    int toSkip = (int) (pos % BLOCK_SIZE); 
    byte[] garbage = new byte[toSkip]; 
    // read bytes into a garbage array for as long as we need (should be max BLOCK_SIZE 
    // bytes 
    int skipped = input.read(garbage, 0, toSkip); 
    while (skipped < toSkip) { 
     skipped += input.read(garbage, 0, toSkip - skipped); 
    } 

    // at this point, the CipherStream is positioned at pos, next read will serve the 
    // plain byte at pos 
} 

Zauważ, że poszukiwanie zasobu delegata jest tu pominięty, a to zależy od tego, co jest pod spodem delegata InputStream. Zauważ także, że początkowa IV musi być uruchomiona przy liczniku 1 (ostatnie 4 bajty).

Unittests pokazują, że to podejście działa (testy porównawcze wydajności zostaną wykonane w pewnym momencie w przyszłości :)).

+1

Licznik w CTR powinien zostać zainicjowany na 0, jeśli kiedykolwiek zostanie przewinięty, istnieje możliwość, że ten sam klucz zostanie ponownie użyty z tym samym 'nonce || Wartość CTR, która jest katastrofalna z punktu widzenia bezpieczeństwa. Powinieneś być rekeying zanim to się stanie. –

+0

Masz rację, trochę zmieniłem swoją implementację, aby faktycznie dostosować się do specyfikacji (nie jestem pewna, dlaczego nie znalazłem/nie poszedłem na początek ...) – akaIDIOT

+0

Hmm, wygrałem ' t pozwól mi już edytować komentarz. [Link do tworzenia IV zgodnie ze specyfikacją] (http://tools.ietf.org/html/rfc3686#section-4). – akaIDIOT