001/* 002 * SVG Salamander 003 * Copyright (c) 2004, Mark McKay 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or 007 * without modification, are permitted provided that the following 008 * conditions are met: 009 * 010 * - Redistributions of source code must retain the above 011 * copyright notice, this list of conditions and the following 012 * disclaimer. 013 * - Redistributions in binary form must reproduce the above 014 * copyright notice, this list of conditions and the following 015 * disclaimer in the documentation and/or other materials 016 * provided with the distribution. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 029 * OF THE POSSIBILITY OF SUCH DAMAGE. 030 * 031 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other 032 * projects can be found at http://www.kitfox.com 033 * 034 * Created on February 12, 2004, 10:34 AM 035 */ 036 037package com.kitfox.svg.xml.cpx; 038 039import com.kitfox.svg.SVGConst; 040import java.io.*; 041import java.util.zip.*; 042import java.security.*; 043import java.util.logging.Level; 044import java.util.logging.Logger; 045 046/** 047 * This class reads/decodes the CPX file format. This format is a simple 048 * compression/encryption transformer for XML data. This stream takes in 049 * encrypted XML and outputs decrypted. It does this by checking for a magic 050 * number at the start of the stream. If absent, it treats the stream as 051 * raw XML data and passes it through unaltered. This is to aid development 052 * in debugging versions, where the XML files will not be in CPX format. 053 * 054 * See http://java.sun.com/developer/technicalArticles/Security/Crypto/ 055 * 056 * @author Mark McKay 057 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a> 058 */ 059public class CPXInputStream extends FilterInputStream implements CPXConsts { 060 061 062 SecureRandom sec = new SecureRandom(); 063 064 Inflater inflater = new Inflater(); 065 066 int xlateMode; 067 068 //Keep header bytes in case this stream turns out to be plain text 069 byte[] head = new byte[4]; 070 int headSize = 0; 071 int headPtr = 0; 072 073 boolean reachedEOF = false; 074 byte[] inBuffer = new byte[2048]; 075 byte[] decryptBuffer = new byte[2048]; 076 077 /** Creates a new instance of CPXInputStream */ 078 public CPXInputStream(InputStream in) throws IOException { 079 super(in); 080 081 //Determine processing type 082 for (int i = 0; i < 4; i++) 083 { 084 int val = in.read(); 085 head[i] = (byte)val; 086 if (val == -1 || head[i] != MAGIC_NUMBER[i]) 087 { 088 headSize = i + 1; 089 xlateMode = XL_PLAIN; 090 return; 091 } 092 } 093 094 xlateMode = XL_ZIP_CRYPT; 095 } 096 097 /** 098 * We do not allow marking 099 */ 100 public boolean markSupported() { return false; } 101 102 /** 103 * Closes this input stream and releases any system resources 104 * associated with the stream. 105 * This 106 * method simply performs <code>in.close()</code>. 107 * 108 * @exception IOException if an I/O error occurs. 109 * @see java.io.FilterInputStream#in 110 */ 111 public void close() throws IOException { 112 reachedEOF = true; 113 in.close(); 114 } 115 116 /** 117 * Reads the next byte of data from this input stream. The value 118 * byte is returned as an <code>int</code> in the range 119 * <code>0</code> to <code>255</code>. If no byte is available 120 * because the end of the stream has been reached, the value 121 * <code>-1</code> is returned. This method blocks until input data 122 * is available, the end of the stream is detected, or an exception 123 * is thrown. 124 * <p> 125 * This method 126 * simply performs <code>in.read()</code> and returns the result. 127 * 128 * @return the next byte of data, or <code>-1</code> if the end of the 129 * stream is reached. 130 * @exception IOException if an I/O error occurs. 131 * @see java.io.FilterInputStream#in 132 */ 133 public int read() throws IOException 134 { 135 final byte[] b = new byte[1]; 136 int retVal = read(b, 0, 1); 137 if (retVal == -1) return -1; 138 return b[0]; 139 } 140 141 /** 142 * Reads up to <code>byte.length</code> bytes of data from this 143 * input stream into an array of bytes. This method blocks until some 144 * input is available. 145 * <p> 146 * This method simply performs the call 147 * <code>read(b, 0, b.length)</code> and returns 148 * the result. It is important that it does 149 * <i>not</i> do <code>in.read(b)</code> instead; 150 * certain subclasses of <code>FilterInputStream</code> 151 * depend on the implementation strategy actually 152 * used. 153 * 154 * @param b the buffer into which the data is read. 155 * @return the total number of bytes read into the buffer, or 156 * <code>-1</code> if there is no more data because the end of 157 * the stream has been reached. 158 * @exception IOException if an I/O error occurs. 159 * @see java.io.FilterInputStream#read(byte[], int, int) 160 */ 161 public int read(byte[] b) throws IOException 162 { 163 return read(b, 0, b.length); 164 } 165 166 /** 167 * Reads up to <code>len</code> bytes of data from this input stream 168 * into an array of bytes. This method blocks until some input is 169 * available. 170 * <p> 171 * This method simply performs <code>in.read(b, off, len)</code> 172 * and returns the result. 173 * 174 * @param b the buffer into which the data is read. 175 * @param off the start offset of the data. 176 * @param len the maximum number of bytes read. 177 * @return the total number of bytes read into the buffer, or 178 * <code>-1</code> if there is no more data because the end of 179 * the stream has been reached. 180 * @exception IOException if an I/O error occurs. 181 * @see java.io.FilterInputStream#in 182 */ 183 public int read(byte[] b, int off, int len) throws IOException 184 { 185 if (reachedEOF) return -1; 186 187 if (xlateMode == XL_PLAIN) 188 { 189 int count = 0; 190 //Write header if appropriate 191 while (headPtr < headSize && len > 0) 192 { 193 b[off++] = head[headPtr++]; 194 count++; 195 len--; 196 } 197 198 return (len == 0) ? count : count + in.read(b, off, len); 199 } 200 201 //Decrypt and inflate 202 if (inflater.needsInput() && !decryptChunk()) 203 { 204 reachedEOF = true; 205 206 //Read remaining bytes 207 int numRead; 208 try { 209 numRead = inflater.inflate(b, off, len); 210 } 211 catch (Exception e) 212 { 213 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); 214 return -1; 215 } 216 217 if (!inflater.finished()) 218 { 219 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, 220 "Inflation imncomplete"); 221 } 222 223 return numRead == 0 ? -1 : numRead; 224 } 225 226 try 227 { 228 return inflater.inflate(b, off, len); 229 } 230 catch (DataFormatException e) 231 { 232 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); 233 return -1; 234 } 235 } 236 237 238 /** 239 * Call when inflater indicates that it needs more bytes. 240 * @return - true if we decrypted more bytes to deflate, false if we 241 * encountered the end of stream 242 */ 243 protected boolean decryptChunk() throws IOException 244 { 245 while (inflater.needsInput()) 246 { 247 int numInBytes = in.read(inBuffer); 248 if (numInBytes == -1) return false; 249// int numDecryptBytes = cipher.update(inBuffer, 0, numInBytes, decryptBuffer); 250// inflater.setInput(decryptBuffer, 0, numDecryptBytes); 251inflater.setInput(inBuffer, 0, numInBytes); 252 } 253 254 return true; 255 } 256 257 /** 258 * This method returns 1 if we've not reached EOF, 0 if we have. Programs 259 * should not rely on this to determine the number of bytes that can be 260 * read without blocking. 261 */ 262 public int available() { return reachedEOF ? 0 : 1; } 263 264 /** 265 * Skips bytes by reading them into a cached buffer 266 */ 267 public long skip(long n) throws IOException 268 { 269 int skipSize = (int)n; 270 if (skipSize > inBuffer.length) skipSize = inBuffer.length; 271 return read(inBuffer, 0, skipSize); 272 } 273 274} 275 276/* 277 import java.security.KeyPairGenerator; 278 import java.security.KeyPair; 279 import java.security.KeyPairGenerator; 280 import java.security.PrivateKey; 281 import java.security.PublicKey; 282 import java.security.SecureRandom; 283 import java.security.Cipher; 284 285 .... 286 287 java.security.Security.addProvider(new cryptix.provider.Cryptix()); 288 289 SecureRandom random = new SecureRandom(SecureRandom.getSeed(30)); 290 KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA"); 291 keygen.initialize(1024, random); 292 keypair = keygen.generateKeyPair(); 293 294 PublicKey pubkey = keypair.getPublic(); 295 PrivateKey privkey = keypair.getPrivate(); 296 */ 297 298/* 299 * 300 *Generate key pairs 301KeyPairGenerator keyGen = 302 KeyPairGenerator.getInstance("DSA"); 303KeyGen.initialize(1024, new SecureRandom(userSeed)); 304KeyPair pair = KeyGen.generateKeyPair(); 305 */