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.jce.provider.BouncyCastleProvider;
23  import org.bouncycastle.openpgp.PGPException;
24  import org.bouncycastle.openpgp.PGPPrivateKey;
25  import org.bouncycastle.openpgp.PGPSecretKey;
26  import org.bouncycastle.openpgp.PGPSignature;
27  import org.bouncycastle.openpgp.PGPSignatureGenerator;
28  import org.bouncycastle.openpgp.PGPUtil;
29  
30  import java.io.ByteArrayOutputStream;
31  import java.io.IOException;
32  import java.io.OutputStream;
33  import java.security.NoSuchAlgorithmException;
34  import java.security.NoSuchProviderException;
35  import java.security.Security;
36  import java.security.SignatureException;
37  
38  /**
39   * Bouncy Castle implementation of the OpenPGP signer.
40   *
41   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
42   */
43  public class BouncyCastleOpenPgpStreamingSigner
44      implements OpenPgpStreamingSigner
45  {
46      private static final String PROVIDER = "BC";
47  
48      private PGPSignatureGenerator sGen;
49  
50      private final ByteArrayOutputStream signatureBytes;
51  
52      private BCPGOutputStream bOut;
53  
54      public BouncyCastleOpenPgpStreamingSigner( String keyId, KeyRing keyRing, boolean asciiArmor )
55          throws OpenPgpException
56      {
57          signatureBytes = new ByteArrayOutputStream();
58          init( asciiArmor, signatureBytes, keyRing, keyId );
59      }
60  
61      public BouncyCastleOpenPgpStreamingSigner( OutputStream signature, String keyId, KeyRing keyRing,
62                                                 boolean asciiArmor )
63          throws OpenPgpException
64      {
65          signatureBytes = null;
66          init( asciiArmor, signature, keyRing, keyId );
67      }
68  
69      private void init( boolean asciiArmor, OutputStream signature, KeyRing keyRing, String keyId )
70          throws OpenPgpException
71      {
72          // TODO: better location for this?
73          Security.addProvider( new BouncyCastleProvider() );
74  
75          OutputStream out;
76          if ( asciiArmor )
77          {
78              out = new ArmoredOutputStream( signature );
79          }
80          else
81          {
82              out = signature;
83          }
84          bOut = new BCPGOutputStream( out );
85  
86          try
87          {
88              PGPSecretKey pgpSec = keyRing.getSecretKey( keyId );
89              PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey( keyRing.getPassword(), PROVIDER );
90              sGen = new PGPSignatureGenerator( pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1, PROVIDER );
91              sGen.initSign( PGPSignature.BINARY_DOCUMENT, pgpPrivKey );
92          }
93          catch ( NoSuchAlgorithmException e )
94          {
95              throw new OpenPgpException(
96                  "Unable to find the correct algorithm for PGP - check that the Bouncy Castle provider is correctly installed",
97                  e );
98          }
99          catch ( NoSuchProviderException e )
100         {
101             throw new OpenPgpException(
102                 "Unable to find the correct provider for PGP - check that the Bouncy Castle provider is correctly installed",
103                 e );
104         }
105         catch ( PGPException e )
106         {
107             // TODO: more details
108             throw new OpenPgpException( "Error calculating detached signature", e );
109         }
110     }
111 
112     public void update( byte[] buf )
113         throws OpenPgpException
114     {
115         update( buf, 0, buf.length );
116     }
117 
118     public void update( byte[] buf, int offset, int length )
119         throws OpenPgpException
120     {
121         try
122         {
123             sGen.update( buf, offset, length );
124         }
125         catch ( SignatureException e )
126         {
127             // TODO: more details
128             throw new OpenPgpException( "Error calculating detached signature", e );
129         }
130     }
131 
132     public byte[] finish()
133         throws OpenPgpException, IOException
134     {
135         try
136         {
137             sGen.generate().encode( bOut );
138         }
139         catch ( PGPException e )
140         {
141             // TODO: more details
142             throw new OpenPgpException( "Error calculating detached signature", e );
143         }
144         catch ( SignatureException e )
145         {
146             // TODO: more details
147             throw new OpenPgpException( "Error calculating detached signature", e );
148         }
149         bOut.close();
150         return signatureBytes != null ? signatureBytes.toByteArray() : null;
151     }
152 }