We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
这次代码实现目标
相关部分加密AES规则
首先写入1K大小扰乱随机头数据
读取源文件的头部1K数据(小于1K则读取所有数据)
使用AES加密算法完成加密后写入加密文件
如果源文件大于1K)剩余文件内容追加进加密文件
基本上实现分为以下步骤
private Single<ResponseBody> downloadFile( Call call ){ return Single.create(subscriber -> { Logger.i( "------Begin To Request Http Thread:%s", Thread.currentThread().getId() ); call.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Logger.e(e,"------- Http Error:%s", e.getMessage() ); subscriber.onError( e ); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { subscriber.onSuccess( response.body() ); } }); }); }
在开发过程中,我需要读取1000多byte的数据。 当ResponseBody转化InputStream流式的时候,其实他的底层实现还是网络字节流,这样read的操作并不一定能读取到和缓冲区一样大小的数据,这样就需要一个“拼包”的处理,如果一次读不到够数的数据,需要把剩下的包凑进去
private byte[] readHeader( InputStream inputStream, int headLength ) throws IOException { byte[] header = new byte[headLength]; int total = 0; int remain = headLength; do { byte[] headerBuffer = new byte[remain]; int read = inputStream.read(headerBuffer); System.arraycopy(headerBuffer,0,header,total,read); total += read; remain = headLength - total; Logger.i("current read head %d / %d , remain %d", total, headLength,remain ); } while (remain > 0); return header; }
Andoid的原生SDK的javax.crypto实现了大多数的加解密的实现,使用起来也很简单
/** * AES 解密 * 使用CBC模式&PKCS7Padding * @param bytes 密文 * @return 明文 */ private byte[] decryptHeader( byte[] bytes ){ String ALGORITHM = "AES/CBC/PKCS7Padding"; try { Cipher cipher = Cipher.getInstance(ALGORITHM); SecretKey secretKey = new SecretKeySpec( HexUtils.hexStringToByteArray( "30980f98296b77f00a55f3c92b35322d898ae2ffcdb906de40336d2cf3d556a0" ) , "AES"); IvParameterSpec ivSpec = new IvParameterSpec(HexUtils.hexStringToByteArray("e5889166bb98ba01e1a6bc9b32dbf3e6")); Logger.i("---Begin decrypt----"); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); return cipher.doFinal(bytes); } catch (InvalidAlgorithmParameterException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) { throw new RuntimeException(e); } }
对整个下载流式处理,包括进度的显示打印等
private Single<File> decryptFile( ResponseBody body, String filePath ){ return Single.create( emitter -> { File file = new File(filePath); int headLength = 1024; if( body.contentLength() > 2048 ){ headLength += 16; } byte[] buffer = new byte[4096]; InputStream inputStream = body.byteStream(); OutputStream outputStream = null; try { this.runOnUiThread( ()-> progressBar.setProgress( 0 )); long totalProcess = 0L; outputStream = new FileOutputStream(file); long skip = inputStream.skip(1024); totalProcess += skip; Logger.i( "Step 1: skip %d",skip ); byte[] header = readHeader( inputStream , headLength ); Logger.i( "Step 2: read header length %d",headLength ); totalProcess += headLength; byte[] decryptedBytes = decryptHeader( header ); Logger.i( "Step 3: decrypt header length %d",decryptedBytes.length ); //Logger.i("decrypt content:%s",HexUtils.bytesToHex(decryptedBytes)); outputStream.write(decryptedBytes, 0, decryptedBytes.length); int read; long contentLength = body.contentLength(); long current = 0; DecimalFormat df = new DecimalFormat("#.##"); do{ current ++; read = inputStream.read(buffer); //Logger.i( "read file length:%d",read ); if( read > 0 ){ totalProcess += read; outputStream.write( buffer,0,read ); if( current % 10 == 0 ){ double percent = totalProcess * 100.00 / contentLength; this.runOnUiThread( ()->{ msg.setText( String.format("%s %%",df.format( percent )) ); if( (int)percent > progressBar.getProgress() ) { progressBar.setProgress((int)percent); } }); } } }while (read > 0); Logger.i( "process file content %s / %s ",totalProcess,contentLength ); outputStream.flush(); emitter.onSuccess( new File(filePath) ); } catch (Exception e) { emitter.onError(e); } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } body.close(); } } ); }
private void productFile( String fileName ){ tv_complete.setText(""); Date start = new Date(); String url = String.format("http://testing.heyshare.cn/download/%s",fileName); Request request = new Request.Builder() .url(url) .get() .build(); Call call = client.newCall(request); String filePath = getExternalFilesDir(null) + "/" + fileName; disposable.add( downloadFile(call) .flatMap( body -> decryptFile(body,filePath) ) .observeOn(AndroidSchedulers.mainThread()) .subscribe( file ->{ msg.setText( String.format( "文件%s解密完成",fileName ) ); Date end = new Date(); Long diff = end.getTime() - start.getTime() ; tv_complete.setText( String.format( "用时 %s 毫秒", diff )); }, throwable -> Logger.e(throwable,"download error"))); }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
这次代码实现目标
相关部分加密AES规则
首先写入1K大小扰乱随机头数据
读取源文件的头部1K数据(小于1K则读取所有数据)
使用AES加密算法完成加密后写入加密文件
如果源文件大于1K)剩余文件内容追加进加密文件
整体思路
基本上实现分为以下步骤
整个流程的串联还是使用ReactiveX Java框架来实现
获取ResponseBody
读取指定长度数据
在开发过程中,我需要读取1000多byte的数据。
当ResponseBody转化InputStream流式的时候,其实他的底层实现还是网络字节流,这样read的操作并不一定能读取到和缓冲区一样大小的数据,这样就需要一个“拼包”的处理,如果一次读不到够数的数据,需要把剩下的包凑进去
AES解密实现
Andoid的原生SDK的javax.crypto实现了大多数的加解密的实现,使用起来也很简单
文件流式处理
对整个下载流式处理,包括进度的显示打印等
对文件操作的整体串联处理
相关仓库
The text was updated successfully, but these errors were encountered: