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 :)).
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. –
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
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