View Javadoc

1   package org.apache.commons.openpgp;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  import org.bouncycastle.bcpg.ArmoredOutputStream;
21  import org.bouncycastle.bcpg.BCPGOutputStream;
22  import org.bouncycastle.bcpg.HashAlgorithmTags;
23  import org.bouncycastle.jce.provider.BouncyCastleProvider;
24  import org.bouncycastle.openpgp.PGPException;
25  import org.bouncycastle.openpgp.PGPPrivateKey;
26  import org.bouncycastle.openpgp.PGPSecretKey;
27  import org.bouncycastle.openpgp.PGPSignature;
28  import org.bouncycastle.openpgp.PGPSignatureGenerator;
29  import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
30  import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
31  import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
32  
33  import java.io.ByteArrayOutputStream;
34  import java.io.IOException;
35  import java.io.OutputStream;
36  import java.security.Security;
37  import java.security.SignatureException;
38  
39  /**
40   * Bouncy Castle implementation of the OpenPGP signer.
41   *
42   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
43   */
44  public class BouncyCastleOpenPgpStreamingSigner
45      implements OpenPgpStreamingSigner
46  {
47      private static final String PROVIDER = "BC";
48  
49      private PGPSignatureGenerator sGen;
50  
51      private final ByteArrayOutputStream signatureBytes;
52  
53      private BCPGOutputStream bOut;
54  
55      public BouncyCastleOpenPgpStreamingSigner( String keyId, KeyRing keyRing, boolean asciiArmor )
56          throws OpenPgpException
57      {
58          signatureBytes = new ByteArrayOutputStream();
59          init( asciiArmor, signatureBytes, keyRing, keyId );
60      }
61  
62      public BouncyCastleOpenPgpStreamingSigner( OutputStream signature, String keyId, KeyRing keyRing,
63                                                 boolean asciiArmor )
64          throws OpenPgpException
65      {
66          signatureBytes = null;
67          init( asciiArmor, signature, keyRing, keyId );
68      }
69  
70      private void init( boolean asciiArmor, OutputStream signature, KeyRing keyRing, String keyId )
71          throws OpenPgpException
72      {
73          // TODO: better location for this?
74          Security.addProvider( new BouncyCastleProvider() );
75  
76          OutputStream out;
77          if ( asciiArmor )
78          {
79              out = new ArmoredOutputStream( signature );
80          }
81          else
82          {
83              out = signature;
84          }
85          bOut = new BCPGOutputStream( out );
86  
87          try
88          {
89              PGPSecretKey pgpSec = keyRing.getSecretKey( keyId );
90              if ( pgpSec == null )
91              {
92                  throw new OpenPgpException( "The key with id '" + keyId + "' was not found in the secret keyring." );
93              }
94              PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(
95                      new JcaPGPDigestCalculatorProviderBuilder().setProvider(PROVIDER).build()).setProvider(PROVIDER).
96                      build(keyRing.getPassword()));
97              sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(),
98                      HashAlgorithmTags.SHA1).setProvider(PROVIDER).setDigestProvider(PROVIDER));
99              sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
100         }
101         catch ( PGPException e )
102         {
103             // TODO: more details
104             throw new OpenPgpException( "Error calculating detached signature", e );
105         }
106     }
107 
108     public void update( byte[] buf )
109         throws OpenPgpException
110     {
111         update( buf, 0, buf.length );
112     }
113 
114     public void update( byte[] buf, int offset, int length )
115         throws OpenPgpException
116     {
117         try
118         {
119             sGen.update( buf, offset, length );
120         }
121         catch ( SignatureException e )
122         {
123             // TODO: more details
124             throw new OpenPgpException( "Error calculating detached signature", e );
125         }
126     }
127 
128     public byte[] finish()
129         throws OpenPgpException, IOException
130     {
131         try
132         {
133             sGen.generate().encode( bOut );
134         }
135         catch ( PGPException e )
136         {
137             // TODO: more details
138             throw new OpenPgpException( "Error calculating detached signature", e );
139         }
140         catch ( SignatureException e )
141         {
142             // TODO: more details
143             throw new OpenPgpException( "Error calculating detached signature", e );
144         }
145         bOut.close();
146         return signatureBytes != null ? signatureBytes.toByteArray() : null;
147     }
148 }