#java #android #encryption
Вопрос:
Я использую эту библиотеку в своем проекте для загрузки файлов, и она отлично работает. Теперь я хочу, чтобы загружаемые мной документы и видео были зашифрованы. Это код, который мне удалось написать после некоторых исследований. Но это выдает ошибку загрузки.
public static class MyStorageResolver extends DefaultStorageResolver {
String ALGORITHM = "Blowfish";
String MODE = "Blowfish/CBC/PKCS5Padding";
String IV = "!a3edr45";
String KEY = "xxxxxxxx";
Cipher cipher;
public MyStorageResolver(Context context) {
super(context, FetchCoreUtils.getFileTempDir(context));
}
@NotNull
@Override
public OutputResourceWrapper getRequestOutputResourceWrapper(@NotNull Downloader.ServerRequest request) {
try {
Key secretKey = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(IV.getBytes()));
return new OutputResourceWrapper() {
RandomAccessFile randomAccessFile = new RandomAccessFile(request.getFile(), "rw");
@Override
public void write(@NotNull byte[] byteArray, int offSet, int length) throws IOException {
randomAccessFile.write(cipher.update(byteArray, offSet, length), offSet, length);
Log.d("download", "raf writing");
}
@Override
public void setWriteOffset(long offset) throws IOException {
int AES_BLOCK_SIZE = 16;
int skip = (int) (offset % AES_BLOCK_SIZE);
long blockOffset = offset - skip;
long numberOfBlocks = blockOffset / AES_BLOCK_SIZE;
BigInteger ivForOffsetAsBigInteger = new BigInteger(1, IV.getBytes()).add(BigInteger.valueOf(numberOfBlocks));
byte[] ivForOffsetByteArray = ivForOffsetAsBigInteger.toByteArray();
IvParameterSpec computedIvParameterSpecForOffset;
if (ivForOffsetByteArray.length < AES_BLOCK_SIZE) {
byte[] resizedIvForOffsetByteArray = BigInteger.valueOf(AES_BLOCK_SIZE).toByteArray();
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);
}
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, computedIvParameterSpecForOffset);
} catch (InvalidAlgorithmParameterException | InvalidKeyException e) {
e.printStackTrace();
}
byte[] skipBuffer = BigInteger.valueOf(skip).toByteArray();
try {
cipher.update(skipBuffer, 0, skip, skipBuffer);
} catch (ShortBufferException e) {
e.printStackTrace();
}
randomAccessFile.seek(offset);
Log.d("download", "raf seeked");
}
@Override
public void flush() {
}
@Override
public void close() throws IOException {
randomAccessFile.close();
}
};
} catch (FileNotFoundException | NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException e) {
Log.d("download", "raf error");
e.printStackTrace();
}
return super.getRequestOutputResourceWrapper(request);
}
}
Я инициализирую выборку следующим образом
FetchConfiguration fetchConfiguration = new FetchConfiguration.Builder(this)
.setDownloadConcurrentLimit(2)
.enableRetryOnNetworkGain(true)
// .setNamespace("TdeskDownloader")
.enableFileExistChecks(true)
.setProgressReportingInterval(500)
.setAutoRetryMaxAttempts(3)
.setNotificationManager(new DefaultFetchNotificationManager(this) {
@Override
public void updateNotification(@NotNull NotificationCompat.Builder notificationBuilder, @NotNull DownloadNotification downloadNotification, @NotNull Context context) {
Intent intent = new Intent(getBaseContext(), DownloadsActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder
.setOnlyAlertOnce(true)
.setColorized(true)
.setNotificationSilent()
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setColor(getResources().getColor(R.color.colorAccent))
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round))
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL);
super.updateNotification(notificationBuilder, downloadNotification, context);
}
@NotNull
@Override
public Fetch getFetchInstanceForNamespace(@NotNull String namespace) {
return fetch;
}
@Override
public boolean shouldCancelNotification(@NotNull DownloadNotification downloadNotification) {
return downloadNotification.getStatus() == Status.CANCELLED;
}
})
.setHttpDownloader(new HttpUrlConnectionDownloader(Downloader.FileDownloaderType.PARALLEL))
.setStorageResolver(new MyStorageResolver(this.getApplicationContext()))
.build();
Fetch.Impl.setDefaultInstanceConfiguration(fetchConfiguration);
fetch = Fetch.Impl.getDefaultInstance();
это журнал ошибок:
2021-07-10 04:19:15.724 E/LibGlobalFetchLib: FileDownloader download:DownloadInfo(id=-1757988576, namespace='LibGlobalFetchLib', url='https://file-examples-com.github.io/uploads/2017/10/file-example_PDF_500_kB.pdf', file='/storage/emulated/0/Download/tdesk/file-example_PDF_500_kB.pdf', group=0, priority=HIGH, headers={}, downloaded=0, total=469513, status=DOWNLOADING, error=NONE, networkType=ALL, created=1625870930995, tag=null, enqueueAction=UPDATE_ACCORDINGLY, identifier=0, downloadOnEnqueue=true, extras={"mime":"application/pdf"}, autoRetryMaxAttempts=0, autoRetryAttempts=3, etaInMilliSeconds=-1, downloadedBytesPerSecond=-1)
java.lang.ArrayIndexOutOfBoundsException: src.length=8 srcPos=0 dst.length=1 dstPos=8 length=8
at java.lang.System.arraycopy(Native Method)
at com.toppersdesk.app.commonUtility$MyStorageResolver$1.setWriteOffset(commonUtility.java:366)
at com.tonyodev.fetch2.downloader.ParallelFileDownloaderImpl.downloadSliceFiles(ParallelFileDownloaderImpl.kt:416)
at com.tonyodev.fetch2.downloader.ParallelFileDownloaderImpl.run(ParallelFileDownloaderImpl.kt:149)
at com.tonyodev.fetch2.downloader.DownloadManagerImpl$start$inlined$synchronized$lambda$1.run(DownloadManagerImpl.kt:103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Может быть, я совершаю какую-то основную ошибку, связанную с классом. Может кто-нибудь, пожалуйста, помочь указать мне, где я делаю ошибки в коде?
Изменить: Я следую примеру в этом выпуске для реализации шифрования с поддержкой резюме. Я никогда не работал с этим классом, поэтому я точно не знаю, в чем проблема с логикой, приведенной в примере кода.
Комментарии:
1. [1] Если ключ находится в вашем исходном коде (например, ваше приложение может расшифровать эти данные без ввода ключа пользователем или взаимодействия с защищенным анклавом по телефону, это не считается . Это все равно что запереть входную дверь на чрезвычайно отличный и дорогой замок и спрятать ключ под коврик. На нем написано «ключ находится под этим ковриком». [2] Укажите полученную ошибку. Трассировка всего стека.
2. @rzwitserloot Вы правы, но это всего лишь начальная реализация шифрования. Как только он заработает нормально, я применю любой безопасный способ хранения ключа. Я включил журнал ошибок. Пожалуйста, проверьте.
3. Сообщение об ошибке объясняет само себя, нет? Вы ссылаетесь
System.arraycopy
на бессмысленные ценности. Отладка в обычном режиме (выведите значения, проверьте, какими, по вашему мнению, они должны были быть, будет несоответствие, теперь вы знаете, где искать).4. @rzwitserloot Я уже знаю из ошибки, что это какая-то проблема с System.arraycopy, но я действительно понятия не имею о логике, используемой в коде. Я следую примеру в этом выпуске для реализации шифрования с поддержкой резюме. Я никогда не работал с этим классом, поэтому я точно не знаю, в чем проблема с логикой, приведенной в примере кода.
5. Вы не можете честно ожидать, что будете отлаживать код, который вы не понимаете. Кто-то написал это; если это ошибка, попросите их исправить ее. Если вы адаптируете код, который вы не понимаете, это обреченное упражнение, вам нужно сначала понять его. Ваши вопросы должны касаться той части, которую вы не понимаете, а не той части, которая выдает ошибку; предположим, что за этой ошибкой стоит еще около 100 ошибок. Теперь осознайте, что, задавая 100 вопросов, вы сожжете много мостов и потратите полгода.