2 回答

TA貢獻1851條經(jīng)驗 獲得超3個贊
我相信您正在尋找對 ctr 加密數(shù)據(jù)的隨機訪問;CipherInputStream 中的 Skip 方法只是不這樣做,并且是“獨立于 Android 版本”(仍在使用;自 api 級別1以來未棄用或替換?。?;
查看 CipherInputStream 類文件;它有一些內(nèi)部屬性:
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;
}
它不會加載新數(shù)據(jù)到 obuffer 或 ibuffer;它只跳過 obuffer 中可用的內(nèi)容(只是增加 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");
}

TA貢獻1842條經(jīng)驗 獲得超13個贊
經(jīng)過研究我得出結(jié)論。你應該用特定的密碼實現(xiàn) InputStream。
private static final int AES_BLOCK_SIZE = 16;
private InputStream mUpstream;
private Cipher mCipher;
private SecretKeySpec mSecretKeySpec;
private IvParameterSpec mIvParameterSpec;
public StreamingCipherInputStream(InputStream inputStream, Cipher cipher,
SecretKeySpec secretKeySpec, IvParameterSpec ivParameterSpec) {
super(inputStream, cipher);
mUpstream = inputStream;
mCipher = cipher;
mSecretKeySpec = secretKeySpec;
mIvParameterSpec = ivParameterSpec; }
@Override
public int read(byte[] b, int off, int len) throws IOException {
return super.read(b, off, len); }
public long forceSkip(long bytesToSkip) throws IOException {
long skipped = mUpstream.skip(bytesToSkip);
try {
int skip = (int) (bytesToSkip % AES_BLOCK_SIZE);
long blockOffset = bytesToSkip - skip;
long numberOfBlocks = blockOffset / AES_BLOCK_SIZE;
BigInteger ivForOffsetAsBigInteger = new BigInteger(1,
mIvParameterSpec.getIV()).add(BigInteger.valueOf(numberOfBlocks));
byte[] ivForOffsetByteArray = ivForOffsetAsBigInteger.toByteArray();
IvParameterSpec computedIvParameterSpecForOffset;
if (ivForOffsetByteArray.length < AES_BLOCK_SIZE) {
byte[] resizedIvForOffsetByteArray = new byte[AES_BLOCK_SIZE];
System.arraycopy(ivForOffsetByteArray, 0, resizedIvForOffsetByteArray,
AES_BLOCK_SIZE - ivForOffsetByteArray.length, ivForOffsetByteArray.length);
computedIvParameterSpecForOffset = new IvParameterSpec(resizedIvForOffsetByteArray);
} else {
computedIvParameterSpecForOffset = new IvParameterSpec(ivForOffsetByteArray, ivForOffsetByteArray.length - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
}
mCipher.init(Cipher.ENCRYPT_MODE, mSecretKeySpec, computedIvParameterSpecForOffset);
byte[] skipBuffer = new byte[skip];
mCipher.update(skipBuffer, 0, skip, skipBuffer);
Arrays.fill(skipBuffer, (byte) 0);
} catch (Exception e) {
return 0;
}
return skipped;
}
@Override
public int available() throws IOException {
return mUpstream.available();}
添加回答
舉報