2013-05-16 24 views
10

Vì chế độ AES ở chế độ CTR rất phù hợp để truy cập ngẫu nhiên, hãy nói rằng tôi có nguồn dữ liệu được tạo bằng CipherOutputStream ở chế độ AES-CTR. Thư viện bên dưới — không phải của tôi — sử dụng một số RandomAccessFile cho phép tìm kiếm một byte bù đắp cụ thể trong tệp.Tìm kiếm trong đầu vào được mã hóa bằng AES-CTR

suy nghĩ ban đầu của tôi sẽ được sử dụng một CipherInputStream với một Cipher khởi tạo với các thông số đúng, nhưng the API for that không làm tìm kiếm và khẳng định không hỗ trợ markreset.

Có một phần của API mà tôi đã bỏ lỡ có thể làm điều này cho tôi hay không, tôi có nên xem xét cấu hình bộ đếm IV/khối của CTR và tạo lại bằng luồng đầu vào tùy chỉnh (có vẻ như khẩu súng ngắn nhắm vào self cho tôi) hoặc có một số cách tiếp cận khác mà tôi đã bỏ lỡ?

Trả lời

9

Đúng vậy, nhận thấy tôi chỉ có một huy hiệu Tumbleweed cho điều này, 'yay' ...

tôi đã kết thúc nhìn lên chính xác cách thức IV được cập nhật trong chế độ CTR. Điều này hóa ra làm một +1 đơn giản cho mỗi khối AES mà nó xử lý. Tôi đã thực hiện đọc theo các dòng sau.

Cho một lớp mà thực hiện một read -like phương pháp mà có thể đọc các byte tiếp theo trong một chuỗi byte được mã hóa và cần phải hỗ trợ tìm kiếm theo thứ tự đó và các biến sau:

  • BLOCK_SIZE: cố định tại 16 (128 bit, kích thước khối AES);
  • cipher: phiên bản javax.crypto.Cipher, được khởi tạo để xử lý AES;
  • delegate: a java.io.InputStream bao bọc tài nguyên được mã hóa cho phép truy cập ngẫu nhiên;
  • input: a javax.crypto.CipherInputStream chúng tôi sẽ phân phát lần đọc từ (luồng sẽ xử lý giải mã).

Phương pháp seek được thực hiện như vậy:

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 
} 

Lưu ý rằng tìm kiếm tài nguyên đại biểu được bỏ qua ở đây, vì điều này phụ thuộc vào những gì là bên dưới các đại biểu InputStream. Cũng lưu ý rằng IV ban đầu bắt buộc phải được bắt đầu tại bộ đếm 1 (4 byte cuối cùng).

Unittests cho thấy cách tiếp cận này hoạt động (hiệu suất điểm chuẩn sẽ được thực hiện tại một số điểm trong tương lai :)).

+1

Số lượt truy cập trong CTR phải được khởi tạo thành 0, nếu nó từng cuộn qua có khả năng là cùng một khóa sẽ được sử dụng lại với cùng một 'nonce || Giá trị CTR' là thảm họa cho bảo mật. Bạn nên được rekeying trước khi điều đó xảy ra. –

+0

Bạn nói đúng, tôi đã thay đổi triển khai của mình một chút trong thời gian trung bình để thực sự tuân thủ thông số kỹ thuật (không chắc chắn lý do tại sao tôi không tìm thấy/đi cho điều đó ngay từ đầu ...) – akaIDIOT

+0

Hmm, won ' để tôi chỉnh sửa bình luận nữa. [Một liên kết đến sự tích tụ của IV theo spec] (http://tools.ietf.org/html/rfc3686#section-4). – akaIDIOT

Các vấn đề liên quan