jdk1.4 打包 加密

在项目中遇到需要使用JDK1.4版本进行文件打包加密的问题,通过寻找解决方案并应用到实际项目中,成功实现了对文件的加密打包。主要关注点在于文件名不能包含中文,只能进行英文加密。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做项目的时候需要对文件打包加密,jdk1.5以后自身就支持打包加密,很可惜,当前这个项目用的是jdk1.4,没办法,只能在网上找相关的资料,最后在老大的帮助下,找到了解决方案,但是有个确定,文件名不能有中文出现,只能对英文加密,以下是这个工具的全部代码:

import java.util.Random;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.modes.SICBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
public class AESEncrypter
{
    public static final int KEY_SIZE_BIT = 256;
   
    public static final int KEY_SIZE_BYTE = KEY_SIZE_BIT / 8;
 
    public static final int ITERATION_COUNT = 1000;
 
    // --------------------------------------------------------------------------
   
    protected byte[] salt;
 
    protected byte[] encryptionKey;
 
    protected byte[] authenticationCode;
   
    protected byte[] pwVerification;
   
    protected CipherParameters cipherParameters;
   
    protected SICBlockCipher aesCipher;
   
    protected int blockSize;
 
    protected int nonce;
   
    protected HMac mac;
   
    /**
     * Setup AES encryption based on pwBytes using WinZipAES approach
     * with SALT and pwVerification bytes based on password+salt.
     */
    public AESEncrypter( byte[] pwBytes ) {    
        PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
        this.salt = createSalt();
        generator.init( pwBytes, salt, ITERATION_COUNT );
 
        // create 2 byte[16] for two keys and one byte[2] for pwVerification 
        // 1. encryption / 2. athentication (via HMAC/hash) /  
        cipherParameters = generator.generateDerivedParameters(KEY_SIZE_BIT*2 + 16);
        byte[] keyBytes = ((KeyParameter)cipherParameters).getKey();
 
        this.encryptionKey = new byte[ KEY_SIZE_BYTE ];
        System.arraycopy( keyBytes, 0, encryptionKey, 0, KEY_SIZE_BYTE );
       
        this.authenticationCode = new byte[ KEY_SIZE_BYTE ];
        System.arraycopy( keyBytes, KEY_SIZE_BYTE, authenticationCode, 0, KEY_SIZE_BYTE );
       
        // based on SALT + PASSWORD (password is probably correct)
        this.pwVerification = new byte[ 2 ];
        System.arraycopy( keyBytes, KEY_SIZE_BYTE*2, pwVerification, 0, 2 );
       
        // create the first 16 bytes of the key sequence again (using pw+salt)
        generator.init( pwBytes, salt, ITERATION_COUNT );      
        cipherParameters = generator.generateDerivedParameters(KEY_SIZE_BIT);
       
        // checksum added to the end of the encrypted data, update on each encryption call
        this.mac = new HMac( new SHA1Digest() );
        mac.init( new KeyParameter(authenticationCode) );
       
        this.aesCipher = new SICBlockCipher(new AESEngine());
        this.blockSize = aesCipher.getBlockSize();
 
        // incremented on each 16 byte block and used as encryption NONCE (ivBytes)
        nonce = 1; 
    }
 
    /**
     * perform pseudo "in-place" encryption
     */
    public void encrypt( byte[] in, int length ) {
        int pos = 0;
        while( pos<in.length && pos<length ) {
            encryptBlock( in, pos, length );
            pos += blockSize;
        }
    }
 
    /**
     * encrypt 16 bytes (AES standard block size) or less
     * starting at "pos" within "in" byte[]
     */
    public void encryptBlock( byte[] in, int pos, int length ) {
        byte[] encryptedIn = new byte[blockSize];
        byte[] ivBytes = ByteArrayHelper.toLEByteArray( nonce++, 16 );
        ParametersWithIV ivParams = new ParametersWithIV(cipherParameters, ivBytes);
        aesCipher.init( true, ivParams );
 
        int remainingCount = length-pos;
        if( remainingCount>=blockSize ) {
            aesCipher.processBlock( in, pos, encryptedIn, 0 );
            System.arraycopy( encryptedIn, 0, in, pos, blockSize );
            mac.update( encryptedIn, 0, blockSize );
        } else {
            byte[] extendedIn = new byte[blockSize];
            System.arraycopy( in, pos, extendedIn, 0, remainingCount );
            aesCipher.processBlock( extendedIn, 0, encryptedIn, 0 );
            System.arraycopy( encryptedIn, 0, in, pos, remainingCount );
            mac.update( encryptedIn, 0, remainingCount );          
        }
    }
   
    /** 16 bytes (AES-256) set in constructor */
    public byte[] getSalt() {
        return salt;
    }
   
    /** 2 bytes for password verification set in constructor */
    public byte[] getPwVerification() {
        return pwVerification;
    }
   
    /** 10 bytes */
    public byte[] getFinalAuthentication() {
        // MAC / based on encIn + PASSWORD + SALT (encryption was successful)
        byte[] macBytes = new byte[ mac.getMacSize() ];
        mac.doFinal( macBytes, 0 );    
        byte[] macBytes10 = new byte[10];
        System.arraycopy( macBytes, 0, macBytes10, 0, 10 );
        return macBytes10;
    }
   
    // --------------------------------------------------------------------------
   
    /**
     * create 16 bytes salt by using each 4 bytes of 2 random 32 bit numbers
     */
    protected static byte[] createSalt() {
        byte[] salt = new byte[16];
        for( int j=0; j<2; j++ ) {
            Random rand = new Random();
            int i = rand.nextInt();
            salt[0+j*4] = (byte)(i>>24);
            salt[1+j*4] = (byte)(i>>16);
            salt[2+j*4] = (byte)(i>>8);
            salt[3+j*4] = (byte)i;
        }
        return salt;
    }
 
}

 

import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.zip.ZipEntry;
public class AesZipEntry extends ZipEntry
{
    public AesZipEntry( ZipEntry zipEntry ) throws Exception {
    super(zipEntry.getName());
    super.setMethod( zipEntry.getMethod() );
    super.setSize( zipEntry.getSize() );
    super.setCompressedSize( zipEntry.getCompressedSize() + 28 );
    super.setTime( zipEntry.getTime() );
    flag |= 1;  // bit0 - encrypted   
    //flag |= 8;  // bit3 - use data descriptor
    }
 
  public boolean useDataDescriptor() { 
    return ((flag & 8) == 8);
  }
 
  protected int flag;
 
  public int getFlag() {
    return this.flag;
  }
 
  protected int offset;
 
  public int getOffset() {
    return offset;
  }
 
  public void setOffset( int offset ) {
    this.offset = offset;
  }
 
  // --------------------------------------------------------------------------
 
  public long getDosTime() {
    return javaToDosTime( getTime() );
  }
 
  protected static long javaToDosTime(long time) {
    Date d = new Date(time);
    Calendar ca = Calendar.getInstance();
    ca.setTime( d );   
    int year = ca.get( Calendar.YEAR );
    if (year < 1980) {
      return (1 << 21) | (1 << 16);
    }
    return (year - 1980) << 25
        | (ca.get(Calendar.MONTH) + 1) << 21
        | ca.get(Calendar.DAY_OF_MONTH) << 16
        | ca.get(Calendar.HOUR_OF_DAY) << 11
        | ca.get(Calendar.MINUTE) << 5
        | ca.get(Calendar.SECOND) >> 1;
  } 
}

 

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class AesZipOutputStream implements ZipConstants
{
    protected OutputStream out;
   
    protected AesZipOutputStream(File file) throws IOException {
        out = new FileOutputStream(file);
    }
 
    protected AesZipOutputStream(OutputStream out) {
        this.out = out;
    }
 
  protected void add( ZipFile inFile, String password ) throws IOException, UnsupportedEncodingException {     
    ZipFileEntryInputStream zfe = new ZipFileEntryInputStream( inFile );
    Enumeration en = inFile.entries();
    while( en.hasMoreElements() ) {
      ZipEntry ze = (ZipEntry)en.nextElement();
      zfe.nextEntry(ze);
      add( ze, zfe, password );
    }
    zfe.close();
  }
 
    protected void add( ZipEntry zipEntry, ZipFileEntryInputStream zipData, String password ) throws IOException, UnsupportedEncodingException {
        AESEncrypter aesEncrypter = new AESEncrypter(password.getBytes("iso-8859-1") );
   
        AesZipEntry entry = null;
  try {
   entry = new AesZipEntry( zipEntry );
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
   
        putNextEntry( entry );
        /* ZIP-file data contains: 1. salt 2. pwVerification 3. ecnryptedContent 4. authenticationCode */
    writeBytes( aesEncrypter.getSalt() );
    writeBytes( aesEncrypter.getPwVerification() );
       
        byte[] data = new byte[1024];
        int read = zipData.read(data);
        while( read!=-1 ) {
      aesEncrypter.encrypt( data, read );
      writeBytes( data, 0, read );    
            read = zipData.read(data);
        }
   
    writeBytes( aesEncrypter.getFinalAuthentication() );   
    }
 
    protected void putNextEntry(AesZipEntry entry) throws IOException {
        entries.add( entry );
 
        entry.setOffset( written );
       
        // file header signature
    writeInt( LOCSIG );
   
        writeFileInfo( entry );
    writeBytes( entry.getName().getBytes("iso-8859-1") );
        writeExtraBytes( entry );
    }
 
    private List entries = new ArrayList();
 
    private final static short ZIP_VERSION = 20;    // version set by java.util.zip
   
    private void writeDirEntry( AesZipEntry entry ) throws IOException {
    writeInt( CENSIG ); //writeBytes( new byte[] { 0x50, 0x4b, 0x01, 0x02 } );  // directory signature
    writeShort( ZIP_VERSION );  // version made by
        writeFileInfo(entry);
       
    writeShort( 0x00 );                     // file comment length                              2 bytes
    writeShort( 0x00 );                     // disk number start (unused)         2 bytes
    writeShort( 0x00 );                     // internal file attributes (unsued)  2 bytes
    writeInt( 0x00 );                           // external file attributes (unused)  4 bytes
       
    writeInt( entry.getOffset() );  // relative offset of local header    4 bytes
 
        writeBytes( entry.getName().getBytes("iso-8859-1") );
 
        writeExtraBytes( entry );
    }
       
    private void writeFileInfo( AesZipEntry entry ) throws IOException {
        writeShort( ZIP_VERSION );  // version needed to extract
       
        // general purpose bit flag - 0x0001 indicates encryption       2 bytes
    writeShort( entry.getFlag() );
       
    writeShort( 0x63 ); // primary compression method - 0x63==encryption
       
    writeInt( entry.getDosTime() );
    /*
    writeBytes( new byte[] { (byte)0x5b, (byte)0x65 } );    // last mod file time
    writeBytes( new byte[] { (byte)0x2d, (byte)0x35 } );    // last mod file date
    */
 
    writeInt( 0x00 ); // CRC-32 / for encrypted files it's 0 as AES/MAC checks integritiy
 
        // 28 bytes is the encryption overhead (caused by 256-bit AES key)
        // 2 bytes pwVerification + 16 bytes SALT + 10 bytes AUTHENTICATION
   
    writeInt( (int)entry.getCompressedSize() );   // compressed size
    writeInt( (int)entry.getSize() );             // uncompressed size
   
        writeShort( entry.getName().length() );         // file name length
    writeShort( 0x0b );                         // extra field length
    }
   
    private void writeExtraBytes( ZipEntry entry ) throws IOException {
        byte[] extraBytes = new byte[11];
        extraBytes[0] = 0x01;
        extraBytes[1] = (byte)0x99;
       
        extraBytes[2] = 0x07;   // data size
        extraBytes[3] = 0x00;   // data size
       
        extraBytes[4]   = 0x02; // version number
        extraBytes[5]   = 0x00; // version number
       
        extraBytes[6] = 0x41;   // vendor id
        extraBytes[7]   = 0x45; // vendor id
       
        extraBytes[8]   = 0x03; // AES encryption strength  - 1=128, 2=192, 3=256
       
        // 41 45 03
       
        // actual compression method - 0x0000==stored (no compression) - 2 bytes
        extraBytes[9]   = (byte)(entry.getMethod() & 0xff);
        extraBytes[10]= (byte)((entry.getMethod() & 0xff00) >> 8);
    writeBytes( extraBytes );
    }
   
    /**
     * Finishes writing the contents of the ZIP output stream without closing the
   * underlying stream. Also closes the stream.
     */
    protected void finish() throws IOException {
        int dirOffset = written;    // central directory (at end of zip file) starts here
           
        int startOfCentralDirectory = written;
       
        Iterator it = entries.iterator();
        while( it.hasNext() ) {
            AesZipEntry entry = (AesZipEntry)it.next();
            writeDirEntry( entry );
        }
    int centralDirectorySize = written - startOfCentralDirectory;
 
    writeInt( ENDSIG ); //writeBytes( new byte[] { 0x50, 0x4b, 0x05, 0x06 } );  // end of central dir signature    4 bytes  (0x06054b50)
   
        writeShort( 0x00 );   // number of this disk                                          2 bytes
        writeShort( 0x00 );   // number of the disk with the start of the central directory   2 bytes
       
    writeShort( entries.size() ); // total number of entries in central directory on this disk  2 bytes
    writeShort( entries.size() ); // total number of entries in the central directory           2 bytes
 
    writeInt( centralDirectorySize );   // size of the central directory   4 bytes
       
        writeInt( dirOffset );  // offset of start of central directory with respect to the starting disk number        4 bytes
        writeShort( 0x00 );     // .ZIP file comment length        2 bytes
 
    out.close();
    }
 
  // --------------------------------------------------------------------------
 
    /** number of bytes written to out */
    protected int written;
   
  protected void writeBytes(byte[] b ) throws IOException {
    out.write(b);
    written+=b.length;
  }
 
  protected void writeShort(int v) throws IOException {
    out.write((v >>> 0) & 0xff);
    out.write((v >>> 8) & 0xff);
    written+=2;
  }
 
  protected void writeInt(long v) throws IOException {
    out.write((int)((v >>>  0) & 0xff));
    out.write((int)((v >>>  8) & 0xff));
    out.write((int)((v >>> 16) & 0xff));
    out.write((int)((v >>> 24) & 0xff));
    written+=4;
  }
 
  protected void writeBytes(byte[] b, int off, int len) throws IOException {
    out.write(b, off, len);
    written+=len;
  }
 
    // --------------------------------------------------------------------------
 
  /**
   * Compress (zip) inFile stored in created outFile.
   * If you need multiple files added to outFile use
   * java's ZipOutStream directly.
   */
  public static void zip( File inFile, File outFile) throws IOException {
    FileInputStream fin = new FileInputStream(inFile);
    FileOutputStream fout = new FileOutputStream(outFile);
    ZipOutputStream zout = new ZipOutputStream(fout);
   
    zout.putNextEntry( new ZipEntry( inFile.getName() ) );
    byte[] buffer = new byte[1024];
    int len;
    while( (len=fin.read(buffer))> 0) {
      zout.write(buffer, 0, len);
    }
    zout.closeEntry();
   
    zout.close();
    fin.close();
  }
 
  /**
   * encrypt zip file contents - encrypted data has the same size as the
   * compressed data, though the file size is increased by 26 bytes for
   * salt and pw-verification bytes
   *
   * @param pathName path to file inclusing filename but NOT file extension (is always ".zip")
   * @param password used to perform the encryption
   * @throws IOException
   */
  public static void encrypt( String pathName, String password ) throws IOException {
    AesZipOutputStream zos = new AesZipOutputStream( new File(pathName+"AES.zip") );
    ZipFile zipFile = new ZipFile(pathName+".zip");
    zos.add( zipFile, password );
    zos.finish();
    zipFile.close();   
  }
 
  public static void zipAndEcrypt( String pathName, String extName, String password ) throws IOException {
    File inFile = new File(pathName + "." + extName);
    File outFile = new File(pathName + ".zip");
    zip( inFile, outFile );
    encrypt( pathName, password );
  }
 
}


public class ByteArrayHelper
{
    public static int fromLEByteArray(byte[] in) {
        int out = 0;
       
        if( in.length==4 ) {   
          out = in[3] & 0xff;
          out = out << 8;
    
          out |= in[2] & 0xff;     
          out = out << 8;
        }
    
        out |= in[1] & 0xff;     
        out = out << 8;
       
        out |= in[0] & 0xff;     
    
        return out;
      }
    
        public static byte[] toLEByteArray(int in) {
            byte[] out = new byte[4];
           
            out[0] = (byte)in;
            out[1] = (byte)(in >> 8);      
            out[2] = (byte)(in >> 16);
            out[3] = (byte)(in >> 24);
           
            return out;
        }
    
        public static byte[] toLEByteArray(int in,int outSize) {
            byte[] out = new byte[outSize];
            byte[] intArray = toLEByteArray(in);
            for( int i=0; i<intArray.length && i<outSize; i++ ) {
                out[i] = intArray[i];
            }
            return out;
        }
    
        public static String toString( byte[] theByteArray ){
            StringBuffer theResult = new StringBuffer();
            for( int i=0; i<theByteArray.length; i++ ) {
                theResult.append( Integer.toHexString(theByteArray[i]&0xff) ).append(' ');
            }
            return theResult.toString();
        }
    
}

 


public interface ZipConstants
{
    /*
     * Header signatures
     */
    static long LOCSIG = 0x04034b50L; // "PK/003/004"
    static long EXTSIG = 0x08074b50L; // "PK/007/008"
    static long CENSIG = 0x02014b50L; // "PK/001/002"
    static long ENDSIG = 0x06054b50L; // "PK/005/006"
  
    /*
     * Header sizes in bytes (including signatures)
     */
    static final int LOCHDR = 30; // LOC header size
    static final int EXTHDR = 16; // EXT header size
    static final int CENHDR = 46; // CEN header size
    static final int ENDHDR = 22; // END header size
  
    /*
     * Local file (LOC) header field offsets
     */
    static final int LOCVER = 4; // version needed to extract
    static final int LOCFLG = 6; // general purpose bit flag
    static final int LOCHOW = 8; // compression method
    static final int LOCTIM = 10; // modification time
    static final int LOCCRC = 14; // uncompressed file crc-32 value
    static final int LOCSIZ = 18; // compressed size
    static final int LOCLEN = 22; // uncompressed size
    static final int LOCNAM = 26; // filename length
    static final int LOCEXT = 28; // extra field length
  
    /*
     * Extra local (EXT) header field offsets
     */
    static final int EXTCRC = 4; // uncompressed file crc-32 value
    static final int EXTSIZ = 8; // compressed size
    static final int EXTLEN = 12; // uncompressed size
  
    /*
     * Central directory (CEN) header field offsets
     */
    static final int CENVEM = 4; // version made by
    static final int CENVER = 6; // version needed to extract
    static final int CENFLG = 8; // encrypt, decrypt flags
    static final int CENHOW = 10; // compression method
    static final int CENTIM = 12; // modification time
    static final int CENCRC = 16; // uncompressed file crc-32 value
    static final int CENSIZ = 20; // compressed size
    static final int CENLEN = 24; // uncompressed size
    static final int CENNAM = 28; // filename length
    static final int CENEXT = 30; // extra field length
    static final int CENCOM = 32; // comment length
    static final int CENDSK = 34; // disk number start
    static final int CENATT = 36; // internal file attributes
    static final int CENATX = 38; // external file attributes
    static final int CENOFF = 42; // LOC header offset
  
    /*
     * End of central directory (END) header field offsets
     */
    static final int ENDSUB = 8; // number of entries on this disk
    static final int ENDTOT = 10; // total number of entries
    static final int ENDSIZ = 12; // central directory size in bytes
    static final int ENDOFF = 16; // offset of first CEN header
    static final int ENDCOM = 20; // zip file comment length
  
}

 

import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
 
class ZipFileEntryInputStream extends FileInputStream implements ZipConstants {
 
  protected long startPos;
 
  protected long endPos;
 
  protected long currentPos;
 
  protected long compressedSize;
 
  //Setting default to true - since if flag is not set - there is nothing to handle => already handled.
  protected boolean dataDescriptorHandled = true;
 
  public long getCompressedSize() {
    return this.compressedSize;
  }
 
  ZipFileEntryInputStream( ZipFile zf ) throws IOException {
    super( zf.getName() );
  }
 
  /**
   * position input stream to start of ZipEntry this instance was created for
   *
   * @throws IOException
   */
  protected void nextEntry( ZipEntry ze ) throws IOException {
    this.compressedSize = ze.getCompressedSize();
    //super.skip( 26 ); // 18 + compressedSize (4) + size (4)
   
    super.skip( 6 );
    byte[] generalPurposeFlagsBytes = new byte[2];
    super.read( generalPurposeFlagsBytes );
    //Check if bit 3 is set - note array-pos 1 is used since LE
    //If it is set - we need to extend by 16 at end of file - check read method
    if( ( generalPurposeFlagsBytes[0] | 0x08 ) == generalPurposeFlagsBytes[0] ) {
     this.dataDescriptorHandled = false;
    }
    super.skip( 18 );  // 6 + 2 + ( 10 + compressedSize (4) + size (4) )
   
    byte[] shortBuffer = new byte[2];
    super.read( shortBuffer );
    int fileNameLength = ByteArrayHelper.fromLEByteArray( shortBuffer );
 
    super.read( shortBuffer );
    int extraFieldLength = ByteArrayHelper.fromLEByteArray( shortBuffer );
 
    startPos = 18 + 12 + fileNameLength + extraFieldLength;
    currentPos = startPos;
    endPos = startPos + this.compressedSize;
 
    skip( fileNameLength + extraFieldLength );
  }
 
  // should work without this, but never trust an OO system
  public int read(byte[] b) throws IOException {
    return this.read(b,0,b.length);
  }
 
  public int read(byte[] b, int off, int len) throws IOException {
    int bytesRead = -1;
    int remainingBytes = (int)(endPos-currentPos);
    if( remainingBytes>0 ) {
      if( currentPos+len<endPos ) {
        bytesRead = super.read(b, off, len);
        currentPos += bytesRead;     
      } else {
        bytesRead = super.read(b, off, remainingBytes );
        currentPos += bytesRead;
     if( ! this.dataDescriptorHandled ) {
      super.skip( 16 );
      this.dataDescriptorHandled = true;
     }
      }
    } else {
     if( ! this.dataDescriptorHandled ) {
      super.skip( 16 );
      this.dataDescriptorHandled = true;
     }
    }
    return bytesRead;
  }
 
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值