View Javadoc

1   
2   package es.caib.signatura.impl;
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.io.UnsupportedEncodingException;
6   
7   /** 
8    * Clase que transforma una firma pkcs7 en un InputStream en formato SMIME.
9    * En concreto, el formato SMIME devuelto es application/pkcs7-mime.
10   *  
11   * @author  3digits
12   * @version 1.0
13   */
14  public class SMIMEPkcs7InputStream extends InputStream {
15  
16  	private static final int CHUNK_SIZE = 48;
17    
18    
19    
20      /** Flag que indica si se han leido todos los bytes de la entrada */
21  	private int status;
22  	static private final int STATUS_IDLE = 0;
23  	static private final int STATUS_HEADER = 1;
24  	static private final int STATUS_BODY = 2;
25  	static private final int STATUS_END = 3;
26  	
27  	int bufferOffset;
28  	byte buffer [];
29  
30  	byte signatureData [];
31  	int signatureDataOffset ;
32  	
33    /**
34     * Crea un nuevo SMIMEInputStream a partir de la firma en pkcs7 y el contentType del MIME
35     * @param pkcs7 el array de bytes que representa el pkcs7
36     */
37      public SMIMEPkcs7InputStream(byte[] pkcs7) {
38        status = STATUS_IDLE;
39        bufferOffset = 0;
40        buffer = null;
41        signatureData = pkcs7;
42        signatureDataOffset = 0;
43        
44      }
45        
46     
47      
48      /* (non-Javadoc)
49       * @see java.io.InputStream#close()
50       */
51      public synchronized void close ()
52      throws IOException {
53          status = STATUS_END;
54      }
55  
56      /* (non-Javadoc)
57       * @see java.io.InputStream#read()
58       */
59      public synchronized int read ()
60      throws IOException {
61      	do {
62      		if ( buffer != null && bufferOffset < buffer.length)
63  	    	{
64  	    		byte b = buffer [ bufferOffset ++ ];
65  	    		return b;
66  	    	} else if (status == STATUS_END) {
67      			return -1;
68  	    	} else {
69  	    		fetchData();
70  	    	}
71  	    	
72      	} while (true);
73      }
74  
75      /* (non-Javadoc)
76       * @see java.io.InputStream#read(byte[], int, int)
77       */
78      public synchronized int read (byte[] targetBuffer, int offset, int length)
79      throws IOException {
80      	do {
81      		if ( buffer != null && bufferOffset < buffer.length)
82  	    	{
83      			int actualLength = buffer.length - bufferOffset;
84      			if ( actualLength > length)
85      				actualLength = length;
86      			System.arraycopy(buffer, bufferOffset, targetBuffer, offset, actualLength);
87      			bufferOffset = bufferOffset + actualLength;
88      			return actualLength;
89  	    	} else if (status == STATUS_END) {
90          		return -1;
91  	    	} else {
92  	    		fetchData();
93  	    	}
94  	    	
95      	} while (true);
96      }
97  
98      /* (non-Javadoc)
99       * @see java.io.InputStream#available()
100      */
101     public synchronized int available()
102     throws IOException {
103     	do {
104     		 if ( buffer != null && bufferOffset < buffer.length)
105 	    	{
106     			return buffer.length - bufferOffset;
107 	    	} else if (status == STATUS_END) {
108 	    		return -1;
109 	    	} else {
110 	    		fetchData ();
111 	    	}
112     	} while (true);
113     }
114 
115 	private void fetchData() throws IOException {
116 		switch (status)
117 		{
118 		case STATUS_IDLE:
119 			buffer = fetchIdle ();
120 			break;
121 		case STATUS_HEADER:
122 			buffer = fetchHeader ();
123 			break;
124 		case STATUS_BODY:
125 			buffer = fetchSignatureBody ();
126 			break;
127 		default:
128 			buffer = null;
129 			break;
130 		}
131 		bufferOffset = 0;
132 	}
133 
134 	private byte [] fetchSignatureBody() {
135 		int len = signatureData.length - signatureDataOffset;
136 		if ( len <= 0)
137 		{
138 			status = STATUS_END;
139 			return null;
140 		}
141 		else if ( len > CHUNK_SIZE )
142 		{
143 			len = CHUNK_SIZE;
144 		}
145 		
146 		byte result []= Base64.toBase64(signatureData, signatureDataOffset, len);
147 		signatureDataOffset = signatureDataOffset + len;
148 		return result;
149 	}
150 
151 
152 	private byte [] fetchHeader() {
153     	try {
154         	status = STATUS_BODY;
155 			return ("Content-Type: application/pkcs7-mime; smime-type=signed-data; name=smime.p7m;\r\n"+
156 					"Content-Transfer-Encoding: base64\r\n"+
157 					"Content-Disposition: attachment; filename=\"smime.p7m\"\r\n"+
158 					"Content-Description: S/MIME Cryptographic Signature\r\n"+
159 					"\r\n").getBytes("ISO-8859-1");
160 		} catch (UnsupportedEncodingException e) {
161 			throw new RuntimeException (e);
162 		}
163 	}
164 
165 
166 	private byte [] fetchIdle() {
167 		status = STATUS_HEADER;
168 		return null;
169 	}
170 
171 
172 	
173 
174   
175     /* (non-Javadoc)
176      * @see java.io.InputStream#skip(long)
177      */
178     public synchronized long skip(long n) throws IOException {
179         for (long i = 0; i < n; i++)
180             if (this.read() < 0) return i;
181         return n;
182     }
183 
184     /* (non-Javadoc)
185      * @see java.io.InputStream#mark(int)
186      */
187     public void mark(int readlimit) {}
188 
189     /* (non-Javadoc)
190      * @see java.io.InputStream#reset()
191      */
192     public void reset() throws IOException {
193         throw new IOException("Base64InputStream does not support mark/reset");
194     }
195 
196     /* (non-Javadoc)
197      * @see java.io.InputStream#markSupported()
198      */
199     public boolean markSupported() { return false; }
200 
201 
202 // Own methods
203     
204     
205 }