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.*; 042import java.util.zip.*; 043import java.security.*; 044import java.util.logging.Level; 045import java.util.logging.Logger; 046import javax.crypto.*; 047 048/** 049 * This class reads/decodes the CPX file format. This format is a simple 050 * compression/encryption transformer for XML data. This stream takes in 051 * encrypted XML and outputs decrypted. It does this by checking for a magic 052 * number at the start of the stream. If absent, it treats the stream as 053 * raw XML data and passes it through unaltered. This is to aid development 054 * in debugging versions, where the XML files will not be in CPX format. 055 * 056 * See http://java.sun.com/developer/technicalArticles/Security/Crypto/ 057 * 058 * @author Mark McKay 059 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a> 060 */ 061public class CPXInputStream extends FilterInputStream implements CPXConsts { 062 063 064 SecureRandom sec = new SecureRandom(); 065 066 Inflater inflater = new Inflater(); 067 068 int xlateMode; 069 070 //Keep header bytes in case this stream turns out to be plain text 071 byte[] head = new byte[4]; 072 int headSize = 0; 073 int headPtr = 0; 074 075 boolean reachedEOF = false; 076 byte[] inBuffer = new byte[2048]; 077 byte[] decryptBuffer = new byte[2048]; 078 079 /** Creates a new instance of CPXInputStream */ 080 public CPXInputStream(InputStream in) throws IOException { 081 super(in); 082 083 //Determine processing type 084 for (int i = 0; i < 4; i++) 085 { 086 int val = in.read(); 087 head[i] = (byte)val; 088 if (val == -1 || head[i] != MAGIC_NUMBER[i]) 089 { 090 headSize = i + 1; 091 xlateMode = XL_PLAIN; 092 return; 093 } 094 } 095 096 xlateMode = XL_ZIP_CRYPT; 097 } 098 099 /** 100 * We do not allow marking 101 */ 102 public boolean markSupported() { return false; } 103 104 /** 105 * Closes this input stream and releases any system resources 106 * associated with the stream. 107 * This 108 * method simply performs <code>in.close()</code>. 109 * 110 * @exception IOException if an I/O error occurs. 111 * @see java.io.FilterInputStream#in 112 */ 113 public void close() throws IOException { 114 reachedEOF = true; 115 in.close(); 116 } 117 118 /** 119 * Reads the next byte of data from this input stream. The value 120 * byte is returned as an <code>int</code> in the range 121 * <code>0</code> to <code>255</code>. If no byte is available 122 * because the end of the stream has been reached, the value 123 * <code>-1</code> is returned. This method blocks until input data 124 * is available, the end of the stream is detected, or an exception 125 * is thrown. 126 * <p> 127 * This method 128 * simply performs <code>in.read()</code> and returns the result. 129 * 130 * @return the next byte of data, or <code>-1</code> if the end of the 131 * stream is reached. 132 * @exception IOException if an I/O error occurs. 133 * @see java.io.FilterInputStream#in 134 */ 135 public int read() throws IOException 136 { 137 final byte[] b = new byte[1]; 138 int retVal = read(b, 0, 1); 139 if (retVal == -1) return -1; 140 return b[0]; 141 } 142 143 /** 144 * Reads up to <code>byte.length</code> bytes of data from this 145 * input stream into an array of bytes. This method blocks until some 146 * input is available. 147 * <p> 148 * This method simply performs the call 149 * <code>read(b, 0, b.length)</code> and returns 150 * the result. It is important that it does 151 * <i>not</i> do <code>in.read(b)</code> instead; 152 * certain subclasses of <code>FilterInputStream</code> 153 * depend on the implementation strategy actually 154 * used. 155 * 156 * @param b the buffer into which the data is read. 157 * @return the total number of bytes read into the buffer, or 158 * <code>-1</code> if there is no more data because the end of 159 * the stream has been reached. 160 * @exception IOException if an I/O error occurs. 161 * @see java.io.FilterInputStream#read(byte[], int, int) 162 */ 163 public int read(byte[] b) throws IOException 164 { 165 return read(b, 0, b.length); 166 } 167 168 /** 169 * Reads up to <code>len</code> bytes of data from this input stream 170 * into an array of bytes. This method blocks until some input is 171 * available. 172 * <p> 173 * This method simply performs <code>in.read(b, off, len)</code> 174 * and returns the result. 175 * 176 * @param b the buffer into which the data is read. 177 * @param off the start offset of the data. 178 * @param len the maximum number of bytes read. 179 * @return the total number of bytes read into the buffer, or 180 * <code>-1</code> if there is no more data because the end of 181 * the stream has been reached. 182 * @exception IOException if an I/O error occurs. 183 * @see java.io.FilterInputStream#in 184 */ 185 public int read(byte[] b, int off, int len) throws IOException 186 { 187 if (reachedEOF) return -1; 188 189 if (xlateMode == XL_PLAIN) 190 { 191 int count = 0; 192 //Write header if appropriate 193 while (headPtr < headSize && len > 0) 194 { 195 b[off++] = head[headPtr++]; 196 count++; 197 len--; 198 } 199 200 return (len == 0) ? count : count + in.read(b, off, len); 201 } 202 203 //Decrypt and inflate 204 if (inflater.needsInput() && !decryptChunk()) 205 { 206 reachedEOF = true; 207 208 //Read remaining bytes 209 int numRead; 210 try { 211 numRead = inflater.inflate(b, off, len); 212 } 213 catch (Exception e) 214 { 215 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); 216 return -1; 217 } 218 219 if (!inflater.finished()) 220 { 221 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, 222 "Inflation imncomplete"); 223 } 224 225 return numRead == 0 ? -1 : numRead; 226 } 227 228 try 229 { 230 return inflater.inflate(b, off, len); 231 } 232 catch (DataFormatException e) 233 { 234 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); 235 return -1; 236 } 237 } 238 239 240 /** 241 * Call when inflater indicates that it needs more bytes. 242 * @return - true if we decrypted more bytes to deflate, false if we 243 * encountered the end of stream 244 */ 245 protected boolean decryptChunk() throws IOException 246 { 247 while (inflater.needsInput()) 248 { 249 int numInBytes = in.read(inBuffer); 250 if (numInBytes == -1) return false; 251// int numDecryptBytes = cipher.update(inBuffer, 0, numInBytes, decryptBuffer); 252// inflater.setInput(decryptBuffer, 0, numDecryptBytes); 253inflater.setInput(inBuffer, 0, numInBytes); 254 } 255 256 return true; 257 } 258 259 /** 260 * This method returns 1 if we've not reached EOF, 0 if we have. Programs 261 * should not rely on this to determine the number of bytes that can be 262 * read without blocking. 263 */ 264 public int available() { return reachedEOF ? 0 : 1; } 265 266 /** 267 * Skips bytes by reading them into a cached buffer 268 */ 269 public long skip(long n) throws IOException 270 { 271 int skipSize = (int)n; 272 if (skipSize > inBuffer.length) skipSize = inBuffer.length; 273 return read(inBuffer, 0, skipSize); 274 } 275 276} 277 278/* 279 import java.security.KeyPairGenerator; 280 import java.security.KeyPair; 281 import java.security.KeyPairGenerator; 282 import java.security.PrivateKey; 283 import java.security.PublicKey; 284 import java.security.SecureRandom; 285 import java.security.Cipher; 286 287 .... 288 289 java.security.Security.addProvider(new cryptix.provider.Cryptix()); 290 291 SecureRandom random = new SecureRandom(SecureRandom.getSeed(30)); 292 KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA"); 293 keygen.initialize(1024, random); 294 keypair = keygen.generateKeyPair(); 295 296 PublicKey pubkey = keypair.getPublic(); 297 PrivateKey privkey = keypair.getPrivate(); 298 */ 299 300/* 301 * 302 *Generate key pairs 303KeyPairGenerator keyGen = 304 KeyPairGenerator.getInstance("DSA"); 305KeyGen.initialize(1024, new SecureRandom(userSeed)); 306KeyPair pair = KeyGen.generateKeyPair(); 307 */