001: /*
002: * $Id: PdfPublicKeySecurityHandler.java 2655 2007-03-15 19:26:36Z xlv $
003: * $Name$
004: *
005: * Copyright 2006 Paulo Soares
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */
050:
051: /**
052: * The below 2 methods are from pdfbox.
053: *
054: * private DERObject createDERForRecipient(byte[] in, X509Certificate cert) ;
055: * private KeyTransRecipientInfo computeRecipientInfo(X509Certificate x509certificate, byte[] abyte0);
056: *
057: * 2006-11-22 Aiken Sam.
058: */
059:
060: /**
061: * Copyright (c) 2003-2006, www.pdfbox.org
062: * All rights reserved.
063: *
064: * Redistribution and use in source and binary forms, with or without
065: * modification, are permitted provided that the following conditions are met:
066: *
067: * 1. Redistributions of source code must retain the above copyright notice,
068: * this list of conditions and the following disclaimer.
069: * 2. Redistributions in binary form must reproduce the above copyright notice,
070: * this list of conditions and the following disclaimer in the documentation
071: * and/or other materials provided with the distribution.
072: * 3. Neither the name of pdfbox; nor the names of its
073: * contributors may be used to endorse or promote products derived from this
074: * software without specific prior written permission.
075: *
076: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
077: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
078: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
079: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
080: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
081: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
082: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
083: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
084: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
085: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
086: *
087: * http://www.pdfbox.org
088: *
089: */package com.lowagie.text.pdf;
090:
091: import java.io.ByteArrayInputStream;
092: import java.io.ByteArrayOutputStream;
093: import java.io.IOException;
094:
095: import java.security.AlgorithmParameterGenerator;
096: import java.security.AlgorithmParameters;
097: import java.security.GeneralSecurityException;
098: import java.security.NoSuchAlgorithmException;
099: import java.security.SecureRandom;
100: import java.security.cert.Certificate;
101: import java.security.cert.X509Certificate;
102:
103: import java.util.ArrayList;
104:
105: import javax.crypto.Cipher;
106: import javax.crypto.KeyGenerator;
107: import javax.crypto.SecretKey;
108:
109: import org.bouncycastle.asn1.ASN1InputStream;
110: import org.bouncycastle.asn1.DERObject;
111: import org.bouncycastle.asn1.DERObjectIdentifier;
112: import org.bouncycastle.asn1.DEROctetString;
113: import org.bouncycastle.asn1.DEROutputStream;
114: import org.bouncycastle.asn1.DERSet;
115: import org.bouncycastle.asn1.cms.ContentInfo;
116: import org.bouncycastle.asn1.cms.EncryptedContentInfo;
117: import org.bouncycastle.asn1.cms.EnvelopedData;
118: import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
119: import org.bouncycastle.asn1.cms.KeyTransRecipientInfo;
120: import org.bouncycastle.asn1.cms.RecipientIdentifier;
121: import org.bouncycastle.asn1.cms.RecipientInfo;
122: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
123: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
124: import org.bouncycastle.asn1.x509.TBSCertificateStructure;
125:
126: /**
127: * @author Aiken Sam (aikensam@ieee.org)
128: */
129: public class PdfPublicKeySecurityHandler {
130:
131: static final int SEED_LENGTH = 20;
132:
133: private ArrayList recipients = null;
134:
135: private byte[] seed = new byte[SEED_LENGTH];
136:
137: public PdfPublicKeySecurityHandler() {
138: KeyGenerator key;
139: try {
140: key = KeyGenerator.getInstance("AES");
141: key.init(192, new SecureRandom());
142: SecretKey sk = key.generateKey();
143: System.arraycopy(sk.getEncoded(), 0, seed, 0, SEED_LENGTH); // create the 20 bytes seed
144: } catch (NoSuchAlgorithmException e) {
145: seed = SecureRandom.getSeed(SEED_LENGTH);
146: }
147:
148: recipients = new ArrayList();
149: }
150:
151: /*
152: * Routine for decode output of PdfContentByte.escapeString(byte[] bytes).
153: * It should be moved to PdfContentByte.
154: */
155:
156: static public byte[] unescapedString(byte[] bytes)
157: throws BadPdfFormatException {
158: ByteArrayOutputStream baos = new ByteArrayOutputStream();
159:
160: int index = 0;
161:
162: if (bytes[0] != '(' && bytes[bytes.length - 1] != ')')
163: throw new BadPdfFormatException(
164: "Expect '(' and ')' at begin and end of the string.");
165:
166: while (index < bytes.length) {
167: if (bytes[index] == '\\') {
168: index++;
169: switch (bytes[index]) {
170: case 'b':
171: baos.write('\b');
172: break;
173: case 'f':
174: baos.write('\f');
175: break;
176: case 't':
177: baos.write('\t');
178: break;
179: case 'n':
180: baos.write('\n');
181: break;
182: case 'r':
183: baos.write('\r');
184: break;
185: case '(':
186: baos.write('(');
187: break;
188: case ')':
189: baos.write(')');
190: break;
191: case '\\':
192: baos.write('\\');
193: break;
194: }
195: } else
196: baos.write(bytes[index]);
197: index++;
198: }
199: return baos.toByteArray();
200: }
201:
202: public void addRecipient(PdfPublicKeyRecipient recipient) {
203: recipients.add(recipient);
204: }
205:
206: protected byte[] getSeed() {
207: return (byte[]) seed.clone();
208: }
209:
210: /*
211: public PdfPublicKeyRecipient[] getRecipients() {
212: recipients.toArray();
213: return (PdfPublicKeyRecipient[])recipients.toArray();
214: }*/
215:
216: public int getRecipientsSize() {
217: return recipients.size();
218: }
219:
220: public byte[] getEncodedRecipient(int index) throws IOException,
221: GeneralSecurityException {
222: //Certificate certificate = recipient.getX509();
223: PdfPublicKeyRecipient recipient = (PdfPublicKeyRecipient) recipients
224: .get(index);
225: byte[] cms = recipient.getCms();
226:
227: if (cms != null)
228: return cms;
229:
230: Certificate certificate = recipient.getCertificate();
231: int permission = recipient.getPermission();//PdfWriter.AllowCopy | PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders | PdfWriter.AllowAssembly;
232: int revision = 3;
233:
234: permission |= revision == 3 ? 0xfffff0c0 : 0xffffffc0;
235: permission &= 0xfffffffc;
236: permission += 1;
237:
238: byte[] pkcs7input = new byte[24];
239:
240: byte one = (byte) (permission);
241: byte two = (byte) (permission >> 8);
242: byte three = (byte) (permission >> 16);
243: byte four = (byte) (permission >> 24);
244:
245: System.arraycopy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input
246:
247: pkcs7input[20] = four;
248: pkcs7input[21] = three;
249: pkcs7input[22] = two;
250: pkcs7input[23] = one;
251:
252: DERObject obj = createDERForRecipient(pkcs7input,
253: (X509Certificate) certificate);
254:
255: ByteArrayOutputStream baos = new ByteArrayOutputStream();
256:
257: DEROutputStream k = new DEROutputStream(baos);
258:
259: k.writeObject(obj);
260:
261: cms = baos.toByteArray();
262:
263: recipient.setCms(cms);
264:
265: return cms;
266: }
267:
268: public PdfArray getEncodedRecipients() throws IOException,
269: GeneralSecurityException {
270: PdfArray EncodedRecipients = new PdfArray();
271: byte[] cms = null;
272: for (int i = 0; i < recipients.size(); i++)
273: try {
274: cms = getEncodedRecipient(i);
275: EncodedRecipients.add(new PdfLiteral(PdfContentByte
276: .escapeString(cms)));
277: } catch (GeneralSecurityException e) {
278: EncodedRecipients = null;
279: } catch (IOException e) {
280: EncodedRecipients = null;
281: }
282:
283: return EncodedRecipients;
284: }
285:
286: private DERObject createDERForRecipient(byte[] in,
287: X509Certificate cert) throws IOException,
288: GeneralSecurityException {
289:
290: String s = "1.2.840.113549.3.2";
291:
292: AlgorithmParameterGenerator algorithmparametergenerator = AlgorithmParameterGenerator
293: .getInstance(s);
294: AlgorithmParameters algorithmparameters = algorithmparametergenerator
295: .generateParameters();
296: ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(
297: algorithmparameters.getEncoded("ASN.1"));
298: ASN1InputStream asn1inputstream = new ASN1InputStream(
299: bytearrayinputstream);
300: DERObject derobject = asn1inputstream.readObject();
301: KeyGenerator keygenerator = KeyGenerator.getInstance(s);
302: keygenerator.init(128);
303: SecretKey secretkey = keygenerator.generateKey();
304: Cipher cipher = Cipher.getInstance(s);
305: cipher.init(1, secretkey, algorithmparameters);
306: byte[] abyte1 = cipher.doFinal(in);
307: DEROctetString deroctetstring = new DEROctetString(abyte1);
308: KeyTransRecipientInfo keytransrecipientinfo = computeRecipientInfo(
309: cert, secretkey.getEncoded());
310: DERSet derset = new DERSet(new RecipientInfo(
311: keytransrecipientinfo));
312: AlgorithmIdentifier algorithmidentifier = new AlgorithmIdentifier(
313: new DERObjectIdentifier(s), derobject);
314: EncryptedContentInfo encryptedcontentinfo = new EncryptedContentInfo(
315: PKCSObjectIdentifiers.data, algorithmidentifier,
316: deroctetstring);
317: EnvelopedData env = new EnvelopedData(null, derset,
318: encryptedcontentinfo, null);
319: ContentInfo contentinfo = new ContentInfo(
320: PKCSObjectIdentifiers.envelopedData, env);
321: return contentinfo.getDERObject();
322: }
323:
324: private KeyTransRecipientInfo computeRecipientInfo(
325: X509Certificate x509certificate, byte[] abyte0)
326: throws GeneralSecurityException, IOException {
327: ASN1InputStream asn1inputstream = new ASN1InputStream(
328: new ByteArrayInputStream(x509certificate
329: .getTBSCertificate()));
330: TBSCertificateStructure tbscertificatestructure = TBSCertificateStructure
331: .getInstance(asn1inputstream.readObject());
332: AlgorithmIdentifier algorithmidentifier = tbscertificatestructure
333: .getSubjectPublicKeyInfo().getAlgorithmId();
334: IssuerAndSerialNumber issuerandserialnumber = new IssuerAndSerialNumber(
335: tbscertificatestructure.getIssuer(),
336: tbscertificatestructure.getSerialNumber().getValue());
337: Cipher cipher = Cipher.getInstance(algorithmidentifier
338: .getObjectId().getId());
339: cipher.init(1, x509certificate);
340: DEROctetString deroctetstring = new DEROctetString(cipher
341: .doFinal(abyte0));
342: RecipientIdentifier recipId = new RecipientIdentifier(
343: issuerandserialnumber);
344: return new KeyTransRecipientInfo(recipId, algorithmidentifier,
345: deroctetstring);
346: }
347: }
|