The entanglement of Zipinputstream and RSA algorithm

Source: Internet
Author: User

Background

A previous article introduced the implementation process for system upgrade operations: The upgrade.sh script was completed by uploading a zip archive and invoking another Java program via RMI. There is a system version information check logic, version information is a piece of XML information through the RSA algorithm encryption, directly packaged into a zip file. The system upgrade operation first decrypts the version description information in the zip file.

There is a strange problem, only my native 360 compression tool generated by the zip file, directly read the ciphertext and decryption will not be error, and WinRAR or 7ZIP tools generated by the compressed file reported decryption exception. This problem has plagued my next year, this is a big hole ah, if not resolved, in case My computer hangs, this function will not work properly. Yesterday, thinking about putting this pit flat, I decided to find out why. Eventually a colleague finds the source and records the pit in IO.

Directly read the zip file

The upgrade operation reads the ciphertext directly from the zip file stream, and the process of reading the zip file directly from Java is as follows:

 Public Static void Readfromzip(String zipfilename) throws ioexception{zipfile ZF =NULL; InputStreaminch=NULL; Zipinputstream Zin =NULL;Try{ZF =NewZipFile (Zipfilename);inch=NewBufferedinputstream (NewFileInputStream (Zipfilename)); Zin =NewZipinputstream (inch); ZipEntry ze =NULL; while((Ze = zin.getnextentry ())! =NULL) {String zipname = Ze.getname ();if(Zipname.contains ("Descriptor")){//Find ciphertext file and readInputStream inputstream = Zf.getinputstream (Ze);byte[] data =New byte[Inputstream.available ()];intLen =0; while(len = inputstream.read (data)) >0) {System. out. println ("Length:"+len); } System. out. println ("Data is:"+arrays.tostring (data)); }            }        }finally{Try{zin.closeentry ();inch. Close ();            Zf.close (); }Catch(IOException E1)            {E1.printstacktrace (); }        }    }

Directly using the Zipinputstream class, iterate through each file in the compressed package, locate the encrypted file, and then read the contents of the file into a byte array. There is a problem with handling this, and Java has different ways of handling the compressed files generated by the various compression tools.

Differences in the corresponding Java implementations for different compression tools

1) WinRAR compressed file, when read with Java IO tool, the instance object of the Zf.getinputstream () stream is:

The read (data) operation of this class is divided two times before it is finished. The print results are as follow:

length:765
Length:3

2) 360 compressed file, when read with Java IO tool, the instance object of the Zf.getinputstream () stream is:

This class reads the data at once. The print results are as follow:

length:768

3) using Bufferedinputstream, after the cache is defined, both streams can read encrypted data at once.

 public  static  byte  []         Bufferedreadfrominputstream  (InputStream inputstream) throws  IOException{        Bufferedinputstream Bufferedinputstream = new  bufferedinputstream (InputStream); byte         [] data = new  byte  [Inputstream.available ()];        int  len = 0 ; while  (len = bufferedinputstream.read (data)) > 0 )    {} return  data; }

This is because the original InputStream read () operation, which writes the data to the internal buffer once every IO read is completed, and when the buffer is defined, the memory is written only when the buffer is full or the data is not read, which guarantees that the length of the data is guaranteed every time the memory is written.

RSA decryption Process

The encrypted files in the compressed file are generated by the RSA algorithm, and the decryption code is as follows:

Private byte[]Decryptdescriptor(InputStream InputStream) {Bytearrayoutputstream BOS =NewBytearrayoutputstream (); X509encodedkeyspec KeySpec;Try{KeySpec =NewX509encodedkeyspec (NewBase64decoder (). Decodebuffer (Encription.key_public)); PublicKey key = Keyfactory.getinstance ("RSA"). Generatepublic (KeySpec); Cipher Cipher = cipher.getinstance ("RSA"); Cipher.init (Cipher.decrypt_mode, key);byte[] data =New byte[Cipher.getoutputsize (Inputstream.available ())];intLen =0;///Direct loop read ciphertext input stream, dofinal decrypted write byte output stream         while(len = bufferedinputstream.read (data)) >0) {Bos.write (cipher.dofinal (data,0, Len)); }returnBos.tobytearray (); }Catch(IOException | invalidkeyspecexception | nosuchalgorithmexception | nosuchpaddingexception | InvalidKeyException | illegalblocksizeexception | Badpaddingexception e) {logger.error ("Decrypting the upgrade profile exception.", e); }finally{Try{Inputstream.close (); }Catch(IOException e) {Logger.error ("Close upgrade description file stream exception.", e); }    }return NULL;}

The decryption code above, directly using InputStream's read (data) method, now reads the file into a byte array, and then calls Dofinal for decryption. Then there is a problem with the WinRAR compression packet, which is an inexplicable read operation.

The RSA decryption algorithm obtains a fixed length based on the length of the data to be decrypted, and then decrypts only the specified length of data each time dofinal.

bytenewbyte[cipher.getOutputSize(inputstream.available())];

This line of code defines the data length, which is 128, based on the true file length of 768. Then the inputstream reads the 768/128=6 times during the read operation, reading 128 bytes of data each time. 360 compressed files conform to this logic. But winrar compressed file because of inexplicable read one more time, resulting in the 6th read length is 125, the last 3 bytes need to read again. and dofinal in the 6th execution of the expected 128 bytes, the result is only the normal 125 bytes of data, so the direct report is abnormal.

Workaround: Through the buffer input stream, so that different compressed files are read the same number of times, to ensure that the dofinal operation can get the correct data. Modify the above code as follows:

Private byte[]Decryptdescriptor(InputStream InputStream) {//using buffered byte streamBufferedinputstream Bufferedinputstream =NewBufferedinputstream (InputStream); ......Try{ ......byte[] data =New byte[Cipher.getoutputsize (Bufferedinputstream. Available ())];intLen =0;//Buffer read ciphertext, dofinal decrypted write bytes in the output stream         while(len = bufferedinputstream. Read (data)) >0) {Bos.write (cipher.dofinal (data,0, Len)); }returnBos.tobytearray (); }Catch(){ ...... }return NULL;}
Revelation

When working with files, try to use Bufferedinputstream, which is efficient and reduces unnecessary IO times. In the event of this problem, it will be solved.

"People are inert animals, if too much to indulge in the gentle village, will weaken the courage and strength of re-enter the storm." "From the beginning of noon in the morning," from Mr. Lu Yao's, the debt owed is always a reminder of his own.

The entanglement of Zipinputstream and RSA algorithm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.