Я полагаю, вы ищете произвольный доступ к зашифрованным данным ctr< /а>; Метод Skip в CipherInputStream просто не делает этого и является «независимым от версии Android» (все еще используется; не устарел и не заменен с уровня API 1!);
Взгляните на файл класса CipherInputStream; Он имеет несколько внутренних свойств:
private Cipher cipher;//the cipher you pass to constructor;
// the underlying input stream
private InputStream input;
/* the buffer holding data that have been read in from the
underlying stream, but have not been processed by the cipher
engine. the size 512 bytes is somewhat randomly chosen */
private byte[] ibuffer = new byte[512];//holds encrypted data
// having reached the end of the underlying input stream
private boolean done = false;
/* the buffer holding data that have been processed by the cipher
engine, but have not been read out */
private byte[] obuffer;//a portion of data that's decrypted but not yet read;
// the offset pointing to the next "new" byte
private int ostart = 0;
// the offset pointing to the last "new" byte
private int ofinish = 0;
и это то, что делает skip в CipherInputStream;
public long skip(long n) throws IOException {
int available = ofinish - ostart;
if (n > available) {
n = available;
}
if (n < 0) {
return 0;
}
ostart += n;
return n;
}
Он не загружает новые данные в obuffer или ibuffer; он пропускает только то, что доступно в обуфере (просто увеличивает ostart);
Это должно сделать это (есть возможности для улучшения):
private static IvParameterSpec calculateIVForOffset(final IvParameterSpec iv,
final long blockOffset) {
final BigInteger ivBI = new BigInteger(1, iv.getIV());
final BigInteger ivForOffsetBI = ivBI.add(BigInteger.valueOf(blockOffset
/ AES_BLOCK_SIZE));
final byte[] ivForOffsetBA = ivForOffsetBI.toByteArray();
final IvParameterSpec ivForOffset;
if (ivForOffsetBA.length >= AES_BLOCK_SIZE) {
ivForOffset = new IvParameterSpec(ivForOffsetBA, ivForOffsetBA.length - AES_BLOCK_SIZE,
AES_BLOCK_SIZE);
} else {
final byte[] ivForOffsetBASized = new byte[AES_BLOCK_SIZE];
System.arraycopy(ivForOffsetBA, 0, ivForOffsetBASized, AES_BLOCK_SIZE
- ivForOffsetBA.length, ivForOffsetBA.length);
ivForOffset = new IvParameterSpec(ivForOffsetBASized);
}
return ivForOffset;
}
long offset = 113845229;// aka a
private void decrypt(Cipher cipher, Uri uri) throws Exception {
long skip_this_much=offset-(offset%16);
InputStream inputStream = getContentResolver().openInputStream(uri);
do{
skip_this_much=skip_this_much-inputStream.skip(skip_this_much);//InputStream.skip does not necessarily skip as much as specified in parameter and returns the actually skipped value;
}while(skip_this_much!=0);//not there yet; keep skipping;
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
int read_this_much=8;
byte[] buffer=new byte[read_this_much+(offset%16)];
cipherInputStream.read(buffer,0,read_this_much+(offset%16));//improve this yourself
buffer= Arrays.copyOfRange(buffer,offset%16,read_this_much+(offset%16));
}
// create cipher for offset
private Cipher createCipher(byte[] iv, byte[] salt, String password) throws Exception {
IvParameterSpec mIvParameterSpec = new IvParameterSpec(iv);
SecretKeySpec mSecretKeySpec = generate(password, salt);
Cipher mCipher = Cipher.getInstance("AES/CTR/NoPadding");
mCipher.init(Cipher.DECRYPT_MODE, mSecretKeySpec, calculateIVForOffset(mIvParameterSpec,offset));
return mCipher;
}
// generate key
private SecretKeySpec generate(String password, byte[] salt) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] key = md.digest(password.getBytes(StandardCharsets.UTF_8));
return new SecretKeySpec(key, "AES");
}
person
kamyar haqqani
schedule
21.08.2019
skip
? Это всегда опасный метод, и API оставляет возможность пропустить меньше байтов, чем запрошено. Также непонятно, что он делает с лежащим в его основе шифром: проходят ли через него байты или нет? Возможно, вам следует пропустить родительский поток. - person Maarten Bodewes   schedule 21.08.2019skip()
работает и передает данные через шифр, но вы обязательно должны проверить возвращаемое значение. Версия OpenJDK никогда не будет пропускать более 512 байт за вызов из-за размера внутреннего буфера. Я не знаю, что делает Android, но, вероятно, это похоже. - person President James K. Polk   schedule 21.08.2019skip()
работает в том смысле, что он правильно пропускает открытый текст, но совершенно бесполезен для вашей проблемы. Либо используйтеread()
и отбрасывайте байты, либо, что гораздо более эффективно, разумно измените IV в соответствии с предложением @MaartenBodewes иseek()
на смещение в интересующем вас файле на границе блока (16 байт). Если поток не доступен для поиска, значит, вы застряли, используяread()
- person President James K. Polk   schedule 22.08.2019