1 31 32 package org.pdfbox.pdmodel.encryption; 33 34 import java.io.ByteArrayInputStream ; 35 import java.io.ByteArrayOutputStream ; 36 import java.io.IOException ; 37 import java.security.AlgorithmParameterGenerator ; 38 import java.security.AlgorithmParameters ; 39 import java.security.GeneralSecurityException ; 40 import java.security.KeyStoreException ; 41 import java.security.MessageDigest ; 42 import java.security.NoSuchAlgorithmException ; 43 import java.security.NoSuchProviderException ; 44 import java.security.SecureRandom ; 45 import java.security.Security ; 46 import java.security.cert.X509Certificate ; 47 import java.util.Iterator ; 48 49 import javax.crypto.Cipher; 50 import javax.crypto.KeyGenerator; 51 import javax.crypto.SecretKey; 52 53 import org.bouncycastle.asn1.ASN1InputStream; 54 import org.bouncycastle.asn1.DERObject; 55 import org.bouncycastle.asn1.DERObjectIdentifier; 56 import org.bouncycastle.asn1.DEROctetString; 57 import org.bouncycastle.asn1.DEROutputStream; 58 import org.bouncycastle.asn1.DERSet; 59 import org.bouncycastle.asn1.cms.ContentInfo; 60 import org.bouncycastle.asn1.cms.EncryptedContentInfo; 61 import org.bouncycastle.asn1.cms.EnvelopedData; 62 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; 63 import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; 64 import org.bouncycastle.asn1.cms.RecipientIdentifier; 65 import org.bouncycastle.asn1.cms.RecipientInfo; 66 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 67 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 68 import org.bouncycastle.asn1.x509.TBSCertificateStructure; 69 import org.bouncycastle.cms.CMSEnvelopedData; 70 import org.bouncycastle.cms.CMSException; 71 import org.bouncycastle.cms.RecipientInformation; 72 import org.bouncycastle.jce.provider.BouncyCastleProvider; 73 import org.pdfbox.cos.COSString; 74 import org.pdfbox.exceptions.CryptographyException; 75 import org.pdfbox.pdmodel.PDDocument; 76 77 88 public class PublicKeySecurityHandler extends SecurityHandler 89 { 90 91 94 public static final String FILTER = "Adobe.PubSec"; 95 96 private static final String SUBFILTER = "adbe.pkcs7.s4"; 97 98 private PublicKeyProtectionPolicy policy = null; 99 100 103 public PublicKeySecurityHandler() 104 { 105 } 106 107 112 public PublicKeySecurityHandler(PublicKeyProtectionPolicy p) 113 { 114 policy = p; 115 this.keyLength = policy.getEncryptionKeyLength(); 116 } 117 118 127 public void decryptDocument(PDDocument doc, DecryptionMaterial decryptionMaterial) 128 throws CryptographyException, IOException 129 { 130 this.document = doc; 131 132 PDEncryptionDictionary dictionary = doc.getEncryptionDictionary(); 133 134 if(dictionary.getLength() != 0) 135 { 136 this.keyLength = dictionary.getLength(); 137 } 138 139 if(!(decryptionMaterial instanceof PublicKeyDecryptionMaterial)) 140 { 141 throw new CryptographyException( 142 "Provided decryption material is not compatible with the document"); 143 } 144 145 PublicKeyDecryptionMaterial material = (PublicKeyDecryptionMaterial)decryptionMaterial; 146 147 try 148 { 149 boolean foundRecipient = false; 150 151 byte[] envelopedData = null; 154 155 byte[][] recipientFieldsBytes = new byte[dictionary.getRecipientsLength()][]; 157 158 int recipientFieldsLength = 0; 159 160 for(int i=0; i<dictionary.getRecipientsLength(); i++) 161 { 162 COSString recipientFieldString = dictionary.getRecipientStringAt(i); 163 byte[] recipientBytes = recipientFieldString.getBytes(); 164 CMSEnvelopedData data = new CMSEnvelopedData(recipientBytes); 165 Iterator recipCertificatesIt = data.getRecipientInfos().getRecipients().iterator(); 166 while(recipCertificatesIt.hasNext()) 167 { 168 RecipientInformation ri = 169 (RecipientInformation)recipCertificatesIt.next(); 170 if(ri.getRID().match(material.getCertificate()) && !foundRecipient) 173 { 174 foundRecipient = true; 175 envelopedData = ri.getContent(material.getPrivateKey(), "BC"); 176 } 177 } 178 recipientFieldsBytes[i] = recipientBytes; 179 recipientFieldsLength += recipientBytes.length; 180 } 181 if(!foundRecipient || envelopedData == null) 182 { 183 throw new CryptographyException("The certificate matches no recipient entry"); 184 } 185 if(envelopedData.length != 24) 186 { 187 throw new CryptographyException("The enveloped data does not contain 24 bytes"); 188 } 189 193 byte[] accessBytes = new byte[4]; 194 System.arraycopy(envelopedData, 20, accessBytes, 0, 4); 195 196 currentAccessPermission = new AccessPermission(accessBytes); 197 currentAccessPermission.setReadOnly(); 198 199 byte[] sha1Input = new byte[recipientFieldsLength + 20]; 201 202 System.arraycopy(envelopedData, 0, sha1Input, 0, 20); 204 205 int sha1InputOffset = 20; 207 for(int i=0; i<recipientFieldsBytes.length; i++) 208 { 209 System.arraycopy( 210 recipientFieldsBytes[i], 0, 211 sha1Input, sha1InputOffset, recipientFieldsBytes[i].length); 212 sha1InputOffset += recipientFieldsBytes[i].length; 213 } 214 215 MessageDigest md = MessageDigest.getInstance("SHA-1"); 216 byte[] mdResult = md.digest(sha1Input); 217 218 encryptionKey = new byte[this.keyLength/8]; 220 System.arraycopy(mdResult, 0, encryptionKey, 0, this.keyLength/8); 221 222 proceedDecryption(); 223 224 225 } 226 catch(CMSException e) 227 { 228 throw new CryptographyException(e); 229 } 230 catch(KeyStoreException e) 231 { 232 throw new CryptographyException(e); 233 } 234 catch(NoSuchProviderException e) 235 { 236 throw new CryptographyException(e); 237 } 238 catch(NoSuchAlgorithmException e) 239 { 240 throw new CryptographyException(e); 241 } 242 243 } 244 245 252 public void prepareDocumentForEncryption(PDDocument doc) throws CryptographyException 253 { 254 255 try 256 { 257 Security.addProvider(new BouncyCastleProvider()); 258 259 PDEncryptionDictionary dictionary = doc.getEncryptionDictionary(); 260 261 dictionary.setFilter(FILTER); 262 dictionary.setLength(this.keyLength); 263 dictionary.setVersion(2); 264 dictionary.setSubFilter(SUBFILTER); 265 266 byte[][] recipientsField = new byte[policy.getRecipientsNumber()][]; 267 268 270 byte[] seed = new byte[20]; 271 272 KeyGenerator key = KeyGenerator.getInstance("AES"); 273 key.init(192, new SecureRandom ()); 274 SecretKey sk = key.generateKey(); 275 System.arraycopy(sk.getEncoded(), 0, seed, 0, 20); 277 278 Iterator it = policy.getRecipientsIterator(); 279 int i = 0; 280 281 282 while(it.hasNext()) 283 { 284 PublicKeyRecipient recipient = (PublicKeyRecipient)it.next(); 285 X509Certificate certificate = recipient.getX509(); 286 int permission = recipient.getPermission().getPermissionBytesForPublicKey(); 287 288 byte[] pkcs7input = new byte[24]; 289 byte one = (byte)(permission); 290 byte two = (byte)(permission >>> 8); 291 byte three = (byte)(permission >>> 16); 292 byte four = (byte)(permission >>> 24); 293 294 System.arraycopy(seed, 0, pkcs7input, 0, 20); 296 pkcs7input[20] = four; 297 pkcs7input[21] = three; 298 pkcs7input[22] = two; 299 pkcs7input[23] = one; 300 301 DERObject obj = createDERForRecipient(pkcs7input, certificate); 302 303 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 304 305 DEROutputStream k = new DEROutputStream(baos); 306 307 k.writeObject(obj); 308 309 recipientsField[i] = baos.toByteArray(); 310 311 i++; 312 } 313 314 dictionary.setRecipients(recipientsField); 315 316 int sha1InputLength = seed.length; 317 318 for(int j=0; j<dictionary.getRecipientsLength(); j++) 319 { 320 COSString string = dictionary.getRecipientStringAt(j); 321 sha1InputLength += string.getBytes().length; 322 } 323 324 325 byte[] sha1Input = new byte[sha1InputLength]; 326 327 System.arraycopy(seed, 0, sha1Input, 0, 20); 328 329 int sha1InputOffset = 20; 330 331 332 for(int j=0; j<dictionary.getRecipientsLength(); j++) 333 { 334 COSString string = dictionary.getRecipientStringAt(j); 335 System.arraycopy( 336 string.getBytes(), 0, 337 sha1Input, sha1InputOffset, string.getBytes().length); 338 sha1InputOffset += string.getBytes().length; 339 } 340 341 MessageDigest md = MessageDigest.getInstance("SHA-1"); 342 343 byte[] mdResult = md.digest(sha1Input); 344 345 this.encryptionKey = new byte[this.keyLength/8]; 346 System.arraycopy(mdResult, 0, this.encryptionKey, 0, this.keyLength/8); 347 348 doc.setEncryptionDictionary(dictionary); 349 doc.getDocument().setEncryptionDictionary(dictionary.encryptionDictionary); 350 351 } 352 catch(NoSuchAlgorithmException ex) 353 { 354 throw new CryptographyException(ex); 355 } 356 catch(NoSuchProviderException ex) 357 { 358 throw new CryptographyException(ex); 359 } 360 catch(Exception e) 361 { 362 e.printStackTrace(); 363 throw new CryptographyException(e); 364 } 365 366 } 367 368 private DERObject createDERForRecipient(byte[] in, X509Certificate cert) 369 throws IOException , 370 GeneralSecurityException 371 { 372 373 String s = "1.2.840.113549.3.2"; 374 375 AlgorithmParameterGenerator algorithmparametergenerator = AlgorithmParameterGenerator.getInstance(s); 376 AlgorithmParameters algorithmparameters = algorithmparametergenerator.generateParameters(); 377 ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream (algorithmparameters.getEncoded("ASN.1")); 378 ASN1InputStream asn1inputstream = new ASN1InputStream(bytearrayinputstream); 379 DERObject derobject = asn1inputstream.readObject(); 380 KeyGenerator keygenerator = KeyGenerator.getInstance(s); 381 keygenerator.init(128); 382 SecretKey secretkey = keygenerator.generateKey(); 383 Cipher cipher = Cipher.getInstance(s); 384 cipher.init(1, secretkey, algorithmparameters); 385 byte[] abyte1 = cipher.doFinal(in); 386 DEROctetString deroctetstring = new DEROctetString(abyte1); 387 KeyTransRecipientInfo keytransrecipientinfo = computeRecipientInfo(cert, secretkey.getEncoded()); 388 DERSet derset = new DERSet(new RecipientInfo(keytransrecipientinfo)); 389 AlgorithmIdentifier algorithmidentifier = new AlgorithmIdentifier(new DERObjectIdentifier(s), derobject); 390 EncryptedContentInfo encryptedcontentinfo = 391 new EncryptedContentInfo(PKCSObjectIdentifiers.data, algorithmidentifier, deroctetstring); 392 EnvelopedData env = new EnvelopedData(null, derset, encryptedcontentinfo, null); 393 ContentInfo contentinfo = 394 new ContentInfo(PKCSObjectIdentifiers.envelopedData, env); 395 return contentinfo.getDERObject(); 396 } 397 398 private KeyTransRecipientInfo computeRecipientInfo(X509Certificate x509certificate, byte[] abyte0) 399 throws GeneralSecurityException , IOException 400 { 401 ASN1InputStream asn1inputstream = 402 new ASN1InputStream(new ByteArrayInputStream (x509certificate.getTBSCertificate())); 403 TBSCertificateStructure tbscertificatestructure = 404 TBSCertificateStructure.getInstance(asn1inputstream.readObject()); 405 AlgorithmIdentifier algorithmidentifier = tbscertificatestructure.getSubjectPublicKeyInfo().getAlgorithmId(); 406 IssuerAndSerialNumber issuerandserialnumber = 407 new IssuerAndSerialNumber( 408 tbscertificatestructure.getIssuer(), 409 tbscertificatestructure.getSerialNumber().getValue()); 410 Cipher cipher = Cipher.getInstance(algorithmidentifier.getObjectId().getId()); 411 cipher.init(1, x509certificate.getPublicKey()); 412 DEROctetString deroctetstring = new DEROctetString(cipher.doFinal(abyte0)); 413 RecipientIdentifier recipId = new RecipientIdentifier(issuerandserialnumber); 414 return new KeyTransRecipientInfo( recipId, algorithmidentifier, deroctetstring); 415 } 416 417 } 418 | Popular Tags |