public static void encrypt(File inputFile, File keyFile, File outputFile) throws IOException {
		FileInputStream in = new FileInputStream(inputFile);
		byte[] input = new byte[(int) (inputFile.length())];
		System.out.println(in.read(input));
		
		//for (int i=0; i<inputFile.length(); i+=4096) {
		//	in.read(b)
		//	in.read(input, i, (int)Math.min(4096, inputFile.length()-i));
		//}
		in.close();
		
		BufferedImage img   = ImageIO.read(keyFile);
		long  bitsToEncrypt   = (inputFile.length()+4)*8;
		long  pixelsAvailable = (img.getWidth()*img.getHeight()) - 2;
		int   bitsPerPixel    = (int)Math.ceil(bitsToEncrypt/(float)pixelsAvailable); // the amount of bits we have to store per pixel to store the input evenly over the whole image
		int[] bitsPerChannel  = new int[] {0,0,0};
		
		int p = 0;
		
		for (int i=0; i<bitsPerPixel; ++i) bitsPerChannel[i%3]++;
		
		int next_input_bit = 0;		// offset in bits to start at with the next pixel
		int next_image_pixel = 2;	// the index of the pixel where we store the next bits
		
		/**
		 * Step 1: In the first pixel we will flip the bits that will be replaced in the other pixels
		 * 		   this way we can know where to look for data.
		 */
		p = img.getRGB(0, 0);
		byte[] first_pixel = new byte[] {
			(byte)((p >> 16) & 0xff), 
			(byte)((p >>  8) & 0xff), 
			(byte)((p)       & 0xff),	
			(byte)((p >> 24) & 0xff),
		};
		
		setChannelEncoding(first_pixel, bitsPerChannel);
		img.setRGB(1, 0, p);
		img.setRGB(0, 0, 
				(first_pixel[3] << 24) |
				(first_pixel[0] << 16) |
				(first_pixel[1] <<  8) |
				(first_pixel[2] <<  0));
		
		/**
		 * Step 2: Concat the length and the data
		 */
		ByteBuffer buf = ByteBuffer.allocate(4 + input.length);
		buf.putInt(input.length);
		buf.put(input);
		buf.rewind();
		
		System.out.println("bits per pixel: " + bitsPerPixel + ":" + bitsPerChannel[0] + "," + bitsPerChannel[1] + "," + bitsPerChannel[2]);
		System.out.println("total bytes: " + input.length);
		
		/**
		 * Step 3: Replace pixels with data :)
		 */
		while (next_input_bit < bitsToEncrypt) {
			p = img.getRGB(next_image_pixel%img.getWidth(), 
						   next_image_pixel/img.getWidth());
			byte[] pixel = new byte[] {
				(byte)((p >> 16) & 0xff), 
				(byte)((p >>  8) & 0xff), 
				(byte)((p >>  0) & 0xff),
				(byte)((p >> 24) & 0xff),
			};
			
			for (int c=0; c<3; ++c) {
				for (int b=0; b<bitsPerChannel[c]; ++b) {
					byte current = buf.get(next_input_bit/8);
					
					int org_bit = ((pixel[c]>>b)&0x01);
					int new_bit = ((current>>(next_input_bit%8))&0x01);
					pixel[c] ^= ((org_bit ^ new_bit) << b);
					
					next_input_bit++;
					if (next_input_bit >= bitsToEncrypt) {
						break;
					}
				}
				
				if (next_input_bit >= bitsToEncrypt) {
					break;
				}
			}
	
			int col = (pixel[3] << 24) |
					  (pixel[0] << 16) |
					  (pixel[1] <<  8) |
					  (pixel[2] <<  0);
			img.setRGB(next_image_pixel%img.getWidth(), next_image_pixel/img.getWidth(), col);
			next_image_pixel++;
		}
		
		/**
		 * Step 4: Write the results to a file
		 */
		outputFile.createNewFile();
		ImageIO.write(img, "png", outputFile);
	}