Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* ************************************************************************
  #
  #  DivConq
  #
  #  http://divconq.com/
  #
  #  Copyright:
  #    Copyright 2014 eTimeline, LLC. All rights reserved.
  #
 #  License:
 #    See the license.txt file in the project's top-level directory for details.
 #
 #  Authors:
 #    * Andy White
 #
 ************************************************************************ */
 package divconq.pgp;
 
 
 import java.util.List;
 
 
 
 
 public class EncryptedFileStream {
 	public static final int MAX_PACKET_SIZE = 32 * 1024;
 	public static final int MAX_PARTIAL_LEN = 0xEF;
 	
     protected String fileName = "temp.bin";
     protected long modificationTime = System.currentTimeMillis();
     //protected PGPPublicKey pubKey = null;
     protected int algorithm = .;
     protected List<PGPKeyEncryptionMethodGeneratormethods = new ArrayList<>();
     
     protected boolean writeFirst = false;
     protected boolean isClosed = false;
     protected SecureRandom rand = new SecureRandom();
     protected byte[] key = null;
     protected Cipher cipher = null;
     protected MessageDigest digest = null;
     
     protected int packetsize = 0;
     protected int packetpos = 0;
     protected ByteBuf packetbuf = null;
     
     protected ByteBuf out = null;    
     protected List<ByteBufreadyBuffers = new ArrayList<>();
 
     public void setFileName(String fileName) {
 		this. = fileName;
 	}
     
     public String getFileName() {
 		return this.;
 	}
     
     public boolean isClosed() {
     	return this.;
     }
     
     public void setModificationTime(long modificationTime) {
 		this. = modificationTime;
 	}
     
     public long getModificationTime() {
 		return this.;
	}
    
    public void setAlgorithm(int algorithm) {
		this. = algorithm;
	}
    
    public int getAlgorithm() {
		return this.;
	}
    
    public void addPublicKey(PGPPublicKey pubKey) {
	}
    
    public void addMethod(PGPKeyEncryptionMethodGenerator v) {
    	this..add(v);
	}
    
    public void ensureBuffer(int size) {
    	if ((this. == null) || (this..writableBytes() < size)) 
    		this.allocNextBuffer(size);
    }
    
    public void allocNextBuffer() {
    	this.allocNextBuffer(1);		// use default
    }
    
    public void allocNextBuffer(int size) {
    	if (this. != null)
    		this..add(this.);
        
    	// buffer must be no larger than 1 GB and should probably be at least 4 KB so we can fit initial sections (packets) 
    	// at top of file
    	
    	// create buffers that are at least 32KB in size
    	
		this. = ..getBufferAllocator().heapBuffer(Math.max(size, 32 * 1024));		// TODO config 
    }
    
		if (this..size() > 0)
			return this..remove(0);
		return null;
	}
    
    public void loadPublicKey(Path keyringthrows IOExceptionPGPException {
    	// TODO move some of this to dcPGPUtil
        PGPPublicKey pubKey = null;
        
        InputStream keyIn = new BufferedInputStream(new FileInputStream(keyring.toFile()));
        
    	PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(org.bouncycastle.openpgp.PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
        //
        // we just loop through the collection till we find a key suitable for encryption, in the real
        // world you would probably want to be a bit smarter about this.
        //
        @SuppressWarnings("rawtypes")
		Iterator keyRingIter = pgpPub.getKeyRings();
        
        while (keyRingIter.hasNext() && (pubKey == null)) {
            PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();
            @SuppressWarnings("rawtypes")
			Iterator keyIter = keyRing.getPublicKeys();
            
            while (keyIter.hasNext() && (pubKey == null)) {
                PGPPublicKey key = (PGPPublicKey)keyIter.next();
                if (key.isEncryptionKey())
                	pubKey = key;
            }
        }
        if (pubKey == null)
        	throw new IllegalArgumentException("Can't find encryption key in key ring.");
    	
	}
    
    // means writing to section that is ciphered only and never compressed, use writeCompressed 
    // most of the time even if not using compression
    public void writeData(byte[] bytesint offsetint len) {
    	// the first time this is called we need to write headers - those headers
    	// call into this method so clear flag immediately
    	if (!this.) {
    		this. = true;
    		this.writeFirstLiteral(len);
    	}
    	
    	int remaining = len;
    	int avail = this. - this.;
    	
    	// packetbuf may have data that has not yet been processed, so if we are doing any writes
    	// we need to write the packet buffer first
    	ByteBuf pbb = this.;
    	
    	if (pbb != null) {
	        int bbremaining = pbb.readableBytes();
	        
	        // only write if there is space available in current packet or if we have a total
	        // amount of data larger than max packet size
    		while ((bbremaining > 0) && ((avail > 0) || (bbremaining + remaining) >= )) {
            	// out of current packet space? create more packets
            	if (avail == 0) {
	            	this. = ;
	            	this. = 0;
	    	        
	    	        this.writeDataInternal((byte);		// partial packet length
	        		
	        		avail = this.;
            	}
            	
            	// figure out how much we can write to the current packet, write it, update indexes
        		int alen = Math.min(availbbremaining);
        		
        		this.writeDataInternal(pbb.array(), pbb.arrayOffset() + pbb.readerIndex(), alen);
        		
        		pbb.skipBytes(alen);
        		bbremaining = pbb.readableBytes();        		
        		this. += alen;        		
        		avail = this. - this.;
        		
    			// our formula always assumes that packetbuf starts at zero offset, anytime
    			// we write out part of the packetbuf we either need to write it all and clear it
        		// or we need to start with a new buffer with data starting at offset 0
        		if (bbremaining == 0) {
        			pbb.clear();
        		}
        		else {
        			npb.writeBytes(pbbbbremaining);
        			this. = npb
        			
        			pbb.release();
        			pbb = npb;
        		}
    		}
    	}
    	
        // only write if there is space available in current packet or if we have a total
        // amount of data larger than max packet size
    	while ((remaining > 0) && ((avail > 0) || (remaining >= ))) {
        	// out of current packet space? create more packets
        	if (avail == 0) {
            	this. = ;
            	this. = 0;
    	        
    	        this.writeDataInternal((byte);		// partial packet length
        		
        		avail = this.;
        	}
        	// figure out how much we can write to the current packet, write it, update indexes
    		int alen = Math.min(availremaining);
    		
    		this.writeDataInternal(bytesoffsetalen);
    		
    		remaining -= alen;
    		offset += alen;
    		this. += alen;    		
    		avail = this. - this.;
    	}
    	
    	// buffer remaining to build larger packet later
    	if (remaining > 0) {
    		if (this. == null)
    		
    		// add to new buffer or add to existing buffer, either way it should be less than max here
    		this..writeBytes(bytesoffsetremaining);
    	}
    }
    
    public void writeData(byte val) {
    	byte[] bytes = new byte[1];
    	bytes[0] = val;
    	
    	this.writeData(bytes, 0, 1);
    }
    
    public void writeData(ByteBuf buf) {
    	this.writeData(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes());
    }
    
    // writes without checking if we need to add a new packet length, useful for headers and tags 
    protected void writeDataInternal(byte[] bytesint offsetint len) {
	    	// hash the unprocessed bytes
	        this..update(bytesoffsetlen);
	        
	        // TODO add debugging support by capturing bytes before compression
	        
	    	// TODO add compression support
	        // if compression flag is on, then send data through compressor
	        
	        // encrypt the data
	    	byte[] cout = this..update(bytesoffsetlen);
	    	
	    	if (cout == null)
	    		return;
	    	
	    	int cpos = 0; 
	    	
	    	// fill present buffer as much as possible
	    	if (this..writableBytes() > 0) { 
	    		int clen = Math.min(cout.lengththis..writableBytes());
	    		this..writeBytes(coutcposclen);
	    		cpos += clen;
	    	}    	
	    	
	    	int remaining = cout.length - cpos;
	    	
	    	if (remaining == 0)  
	    		return;
	    	
	    	this.ensureBuffer(remaining);
			this..writeBytes(coutcposremaining);
		}
		else {
	        
	        // TODO add debugging support by capturing bytes before compression
	        
	    	// TODO add compression support
	        // if compression flag is on, then send data through compressor
	        
	    	// fill present buffer as much as possible
	    	if (this..writableBytes() > 0) { 
	    		int clen = Math.min(lenthis..writableBytes());
	    		this..writeBytes(bytesoffsetclen);
	    		offset += clen;
	    		len -= clen;
	    	}    	
	    	
	    	if (len == 0)  
	    		return;
	    	
	    	this.ensureBuffer(len);
			this..writeBytes(bytesoffsetlen);
		}
    }
    
    protected void writeDataInternal(byte val) {
    	byte[] bytes = new byte[1];
    	bytes[0] = val;
    	
    	this.writeDataInternal(bytes, 0, 1);
    }
    // call before putting any file data in buffer
			// *******************************************************************
			// public key packet(s)
			// *******************************************************************
			if ((.size() == 1) && (.get(0) instanceof PBEKeyEncryptionMethodGenerator)) {
			    
			    this. = method.getKey();
			    
		        ContainedPacket packet1 = method.generate(null);
		        
		        byte[] encoded1 = packet1.getEncoded();
		        this.ensureBuffer(encoded1.length);
		        
		        this..writeBytes(encoded1);
			}
			else  {
				this. = org.bouncycastle.openpgp.PGPUtil.makeRandomKey();
			    
		        byte[] sessionInfo = new byte[. + 3];
		        // add algorithm
		        sessionInfo[0] = (byte;
		        
		        // add key
		        System.arraycopy(, 0, sessionInfo, 1, .);
		        
		        // add checksum 
		        int check = 0;
		        for (int i = 1; i != sessionInfo.length - 2; i++)
		            check += sessionInfo[i] & 0xff;
		        sessionInfo[sessionInfo.length - 2] = (byte)(check >> 8);
		        sessionInfo[sessionInfo.length - 1] = (byte)(check);
			    for (PGPKeyEncryptionMethodGenerator method : ) {
			        ContainedPacket packet1 = method.generate(sessionInfo);
			        
			        byte[] encoded1 = packet1.getEncoded();
			        this.ensureBuffer(encoded1.length);
			        
			        this..writeBytes(encoded1);
			    }
			}
			// *******************************************************************
			// encrypt packet, add IV to encryption though
			// *******************************************************************
	        
	        this.ensureBuffer(3);
	        
	        this..writeByte(0xC0 | .);
	        this..writeByte(0);  // unknown size
	    	this..writeByte(1);        // version number
	        // ******************** start encryption **********************
	        String cName = PGPUtil.getSymmetricCipherName() + "/CFB/NoPadding";
	    	DefaultJcaJceHelper helper = new DefaultJcaJceHelper();
	    	
	        this. = helper.createCipher(cName);
	        
	        byte[] iv = new byte[this..getBlockSize()];
	        this..init(., PGPUtil.makeSymmetricKey(), new IvParameterSpec(iv));
	        
	        this. = MessageDigest.getInstance("SHA-1");
	        
	        // --- encrypt checksum for encrypt packet, part of the encrypted output --- 
	        
	        byte[] inLineIv = new byte[this..getBlockSize() + 2];
	        
	        .nextBytes(inLineIv);
	        
	        inLineIv[inLineIv.length - 1] = inLineIv[inLineIv.length - 3];
	        inLineIv[inLineIv.length - 2] = inLineIv[inLineIv.length - 4];
	        
	        this.writeDataInternal(inLineIv, 0, inLineIv.length);
		}
        // ******************* Optionally add Compression **************************
        
        // TODO set compressor 
        
        // ******************** Literal data packet ***********************
        
		this.ensureBuffer(1);
        this.writeDataInternal((byte) (0xC0 | .));
	}
    
	public void writeFirstLiteral(int dataLength) {
        // --- data packet ---
        byte[] encName = Utf8Encoder.encode(this.);
        
        int headerlen =  1        // format
				+ 1 		// name length
encName.length	// file name
				+ 4; 		// time
        // if less than 512 assume this is all there will be, because we cannot stream with numbers smaller than 512 for initial
        if (dataLength < (512 - headerlen)) {
        	this. = dataLength + headerlen;
	        
	    	this.writeDataPacketLength(this.);
        }
        else {
	        int length = dataLength + headerlen;
	        int power = 0;
	        
	        for (power = 0; (length != 1) && (power < 16); power++)
	            length >>>= 1;
	        
        	this. = 1 << power;
	        
	        this.writeDataInternal((byte) (0xE0 | power));		// partial packet length
        }
        
        byte[] hdr = new byte[headerlen];
        
        hdr[0] = (byte).;		// data format
        hdr[1] = (byte)encName.length;			// file name
        
        for (int i = 0; i < encName.lengthi++)
        	hdr[2 + i] = encName[i];
        
        hdr[headerlen - 4] = (byte)(this. >> 24);
        hdr[headerlen - 3] = (byte)(this. >> 16);
        hdr[headerlen - 2] = (byte)(this. >> 8);
        hdr[headerlen - 1] = (byte)this.;       
        
        this.writeDataInternal(hdr, 0, headerlen);
        
        this. = headerlen;
	}
    /*
     * Finish writing out the current packet and add protection packet
     */
    public void close() throws PGPException {
    	if (this.)
    		return;
    	
    	this. = true;
    	
		if (this. != null) {
			// flush data if any packet space is available
	    	this.writeData(new byte[0], 0, 0);
	    	
        	this. = this..readableBytes();
	        this. = 0;
	        
	        // even if zero, this is fine, we need a final packet
	    	this.writeDataPacketLength(this.);		
	    	
	    	if (this. > 0)
	    		this.writeData(new byte[0], 0, 0);
	    	
			this. = null;
		}
	    	this.ensureBuffer(22);
	    	
			this.writeDataInternal((byte) 20);	// length of SHA-1 is always 20 bytes
	        this.writeDataInternal(this..digest(), 0, 20);
	        
	        // TODO final compression, pass into doFinal below
	        
	        byte[] fcipher;
	        
			try {
				fcipher = this..doFinal();
			catch (Exception x) {
				throw new PGPException("Problem with PGP cipher"x);
			}
	        
	        this.ensureBuffer(fcipher.length);
	        this..writeBytes(fcipher);		// write raw
		}
		else {
	        // TODO final compression, if any
		}
        this..add(this.);
        this. = null;
    }
    
    public void writeDataPacketLength(int bodyLen) {
        if (bodyLen < 192) {
            this.writeDataInternal((bytebodyLen);
        }
        else if (bodyLen <= 8383) {
            bodyLen -= 192;
                    
            int oct1 = ((bodyLen >> 8) & 0xff) + 192;
            
            this.writeDataInternal((byteoct1);
            this.writeDataInternal((bytebodyLen);
        }
        else {
        	this.writeDataInternal((byte) 0xff);
        	this.writeDataInternal((byte) (bodyLen >> 24));
        	this.writeDataInternal((byte) (bodyLen >> 16));
        	this.writeDataInternal((byte) (bodyLen >> 8));
        	this.writeDataInternal((bytebodyLen);
        }
    }
    
    /*
     * Reverse length:
     * 
        if (newPacket)
        {
            tag = hdr & 0x3f;
            int    l = this.read();
            if (l < 192)
            {
                bodyLen = l;
            }
            else if (l <= 223)
            {
                int b = in.read();
                bodyLen = ((l - 192) << 8) + (b) + 192;
            }
            else if (l == 255)
            {
                bodyLen = (in.read() << 24) | (in.read() << 16) |  (in.read() << 8)  | in.read();
            }
            else
            {
                partial = true;
                bodyLen = 1 << (l & 0x1f);
            }
        }
        else
        {
            int lengthType = hdr & 0x3;
            tag = (hdr & 0x3f) >> 2;
            switch (lengthType)
            {
            case 0:
                bodyLen = this.read();
                break;
            case 1:
                bodyLen = (this.read() << 8) | this.read();
                break;
            case 2:
                bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read();
                break;
            case 3:
                partial = true;
                break;
            default:
                throw new IOException("unknown length type encountered");
            }
        }
     * 
     */
New to GrepCode? Check out our FAQ X