View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.vafer.jdeb.signing;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.InputStreamReader;
22  import java.io.OutputStream;
23  import java.security.NoSuchAlgorithmException;
24  import java.security.NoSuchProviderException;
25  import java.security.Security;
26  import java.security.SignatureException;
27  import java.util.Iterator;
28  
29  import org.bouncycastle.bcpg.ArmoredOutputStream;
30  import org.bouncycastle.bcpg.BCPGOutputStream;
31  import org.bouncycastle.jce.provider.BouncyCastleProvider;
32  import org.bouncycastle.openpgp.PGPException;
33  import org.bouncycastle.openpgp.PGPPrivateKey;
34  import org.bouncycastle.openpgp.PGPSecretKey;
35  import org.bouncycastle.openpgp.PGPSecretKeyRing;
36  import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
37  import org.bouncycastle.openpgp.PGPSignature;
38  import org.bouncycastle.openpgp.PGPSignatureGenerator;
39  import org.bouncycastle.openpgp.PGPUtil;
40  
41  /**
42   * Utils to do the signing with OpenPGP
43   * 
44   * @author Torsten Curdt <tcurdt@vafer.org>
45   */
46  
47  public final class SigningUtils {
48  
49      private static PGPSecretKey getSecretKey( final InputStream pInput, final String pKey ) throws IOException, PGPException {
50  
51          final PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(pInput));
52  
53      	final Iterator rIt = pgpSec.getKeyRings();
54  
55  		while (rIt.hasNext()) {
56  			final PGPSecretKeyRing kRing = (PGPSecretKeyRing) rIt.next();
57  			final Iterator kIt = kRing.getSecretKeys();
58  
59  			while (kIt.hasNext()) {
60  				final PGPSecretKey k = (PGPSecretKey) kIt.next();
61  
62  				if (k.isSigningKey() && Long.toHexString(k.getKeyID() & 0xFFFFFFFFL).equals(pKey.toLowerCase())) {
63  					return k;
64  				}
65  			}
66  		}
67  
68  		return null;
69  	}
70  
71  	/**
72  	 * Create a clear sign signature over the input data. (Not detached)
73  	 * 
74  	 * @param pInput
75  	 * @param pKeyring
76  	 * @param pKey
77  	 * @param pPassphrase
78  	 * @param pOutput
79  	 * @throws IOException
80  	 * @throws PGPException
81  	 * @throws NoSuchProviderException
82  	 * @throws NoSuchAlgorithmException
83  	 * @throws SignatureException
84  	 */
85  	public static void clearSign( final InputStream pInput, final InputStream pKeyring, final String pKey, final String pPassphrase, final OutputStream pOutput ) throws IOException, PGPException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
86  		
87  		Security.addProvider( new BouncyCastleProvider() );
88          
89          final PGPSecretKey secretKey = getSecretKey(pKeyring, pKey);
90          final PGPPrivateKey privateKey = secretKey.extractPrivateKey(pPassphrase.toCharArray(), "BC");
91                  
92          final int digest = PGPUtil.SHA1;
93  
94          final PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(secretKey.getPublicKey().getAlgorithm(), digest, "BC");
95          signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, privateKey);
96  
97  //        final PGPSignatureSubpacketGenerator subpackageGenerator = new PGPSignatureSubpacketGenerator();
98  //
99  //        final Iterator it = secretKey.getPublicKey().getUserIDs();
100 //        if (it.hasNext()) {
101 //            subpackageGenerator.setSignerUserID(false, (String)it.next());
102 //            signatureGenerator.setHashedSubpackets(subpackageGenerator.generate());
103 //        }
104 	
105         final ArmoredOutputStream armoredOutput = new ArmoredOutputStream(pOutput);
106         
107         armoredOutput.beginClearText(digest);
108 
109         final BufferedReader reader = new BufferedReader(new InputStreamReader(pInput));
110 
111         final byte[] newline = "\r\n".getBytes("UTF-8");
112         
113         processLine(reader.readLine(), armoredOutput, signatureGenerator);
114         
115         while(true) {
116         	final String line = reader.readLine();
117         	
118         	if (line == null) {
119             	armoredOutput.write(newline);
120         		break;
121         	}
122         	        	
123         	armoredOutput.write(newline);
124         	signatureGenerator.update(newline);
125 
126             processLine(line, armoredOutput, signatureGenerator);        	
127         }
128         
129         armoredOutput.endClearText();
130         
131         final BCPGOutputStream pgpOutput = new BCPGOutputStream(armoredOutput);
132         
133         signatureGenerator.generate().encode(pgpOutput);
134 
135         armoredOutput.close();
136 		
137 	}
138 
139 
140 	private static void processLine( final String pLine, final ArmoredOutputStream pArmoredOutput, final PGPSignatureGenerator pSignatureGenerator ) throws IOException, SignatureException {
141 
142 		if (pLine == null) {
143 			return;
144 		}
145 		
146 		final char[] chars = pLine.toCharArray();
147     	int len = chars.length;
148 
149     	while(len > 0) {
150     		if (!Character.isWhitespace(chars[len-1])) {
151     			break;
152     		}
153     		len--;
154     	}
155 
156     	final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
157     	
158     	pArmoredOutput.write(data);
159     	pSignatureGenerator.update(data);
160 	}
161 }