Author: ogusakov Date: Mon Aug 11 17:08:39 2008 New Revision: 684996 URL: http://svn.apache.org/viewvc?rev=684996&view=rev Log: implemented PGP signatures, changed StreamVerifier modus operandi to get initialized with signature upfront as crypto signature needs that. Changed http client to follow this new paradigm
Added: maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/Messages.properties maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpHelper.java maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifier.java maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifierFactory.java Added: maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/Messages.properties URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/Messages.properties?rev=684996&view=auto ============================================================================== --- maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/Messages.properties (added) +++ maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/Messages.properties Mon Aug 11 17:08:39 2008 @@ -0,0 +1,23 @@ +null.input.stream=input stream should not be null +bad.key.id=bad hex key id: {0} + +no.secret.key=no secret key {0} in the specified keyring +no.public.key=no public key {0} in the specified keyring + +null.private.key=supplied key cannot be null + +null.verify.signature=out of sequence call to verify signature: verifier has not been initialized yet + +bad.verify.signature.state=out of sequence call to produce signature: verifier has not been initialized yet + +no.signatures.in.stream=no signatures found in the input streamn +no.objects.in.stream=no pgp objects found in the input streamn + +bad.factory.init.verify=cannot initialize signature verification factory without trusted ring +bad.factory.init.verify.empty=trusted ring read in is null, cannot proceed +bad.factory.init.generate=cannot initialize signature generation factory without secret key + +no.stream.processor=neither signature generator nor signature verifier has been initialized. Don't know what to do. +no.trusted.ring=trusted ring seem to be empty. There is no one I can trust, so signature verification is pointless. +no.signature.string=there is signature supplied, so signature verification is pointless. + Added: maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpHelper.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpHelper.java?rev=684996&view=auto ============================================================================== --- maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpHelper.java (added) +++ maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpHelper.java Mon Aug 11 17:08:39 2008 @@ -0,0 +1,173 @@ +package org.apache.maven.mercury.crypto.pgp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.SignatureException; +import java.util.Iterator; + +import org.apache.maven.mercury.crypto.api.StreamVerifierException; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.BCPGOutputStream; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPLiteralData; +import org.bouncycastle.openpgp.PGPCompressedDataGenerator; +import org.bouncycastle.openpgp.PGPCompressedData; +import org.bouncycastle.openpgp.PGPLiteralDataGenerator; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPOnePassSignatureList; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.PGPUtil; +import org.codehaus.plexus.i18n.DefaultLanguage; +import org.codehaus.plexus.i18n.Language; + +/** + * PGP helper - collection of utility methods, loosely based on one of the + * Bouncy Castle's SignedFileProcessor.java + * + */ +public class PgpHelper +{ + public static final String PROVIDER = "BC"; + public static final String EXTENSION = "asc"; + + private static final Language lang = new DefaultLanguage( PgpHelper.class ); + //--------------------------------------------------------------------------------- + static + { + Security.addProvider( new BouncyCastleProvider() ); + } + //--------------------------------------------------------------------------------- + /** + * load a key ring stream and find the secret key by hex id + * + * @param in PGP keystore + * @param hexId key id + * @return + * @throws IOException + * @throws PGPException + */ + public static PGPSecretKeyRing readKeyRing( InputStream in, String hexId ) + throws IOException, PGPException + { + if( in == null ) + throw new IllegalArgumentException( lang.getMessage( "null.input.stream" ) ); + + if( hexId == null || hexId.length() < 16 ) + throw new IllegalArgumentException( lang.getMessage( "bad.key.id", hexId ) ); + + long id = hexToId( hexId ); + + in = PGPUtil.getDecoderStream( in ); + + PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection( in ); + + Iterator<PGPSecretKeyRing> ringIt = pgpSec.getKeyRings(); + + while( ringIt.hasNext() ) + { + PGPSecretKeyRing keyRing = ringIt.next(); + PGPSecretKey key = keyRing.getSecretKey( id ); + if( key != null ) + return keyRing; + } + + throw new IllegalArgumentException( lang.getMessage( "no.secret.key", hexId ) ); + } + //--------------------------------------------------------------------------------- + public static long hexToId( String hexId ) + { + return Long.parseLong( hexId, 16 ); + } + //--------------------------------------------------------------------------------- + public static PGPSignature readSignature( InputStream inS ) + throws IOException, PGPException + { + if( inS == null ) + throw new IllegalArgumentException( "null.input.stream" ); + + InputStream in = inS; + in = PGPUtil.getDecoderStream( in ); + + PGPObjectFactory pgpObjectFactory = new PGPObjectFactory( in ); + PGPSignatureList sigList = null; + + Object pgpObject = pgpObjectFactory.nextObject(); + + if( pgpObject == null ) + throw new PGPException( lang.getMessage( "no.objects.in.stream" ) ); + + if( pgpObject instanceof PGPCompressedData ) + { + PGPCompressedData cd = (PGPCompressedData)pgpObject; + + pgpObjectFactory = new PGPObjectFactory( cd.getDataStream() ); + + sigList = (PGPSignatureList)pgpObjectFactory.nextObject(); + } + else + { + sigList = (PGPSignatureList)pgpObject; + } + + if( sigList.size() < 1 ) + throw new PGPException( lang.getMessage( "no.signatures.in.stream" ) ); + + PGPSignature sig = sigList.get(0); + + return sig; + } + //--------------------------------------------------------------------------------- + public static String streamToString( InputStream in ) + throws IOException + { + if( in == null ) + return null; + + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + int b = 0; + while( (b = in.read()) != -1 ) + ba.write( b ); + + return ba.toString(); + } + //--------------------------------------------------------------------------------- + public static String fileToString( String fileName ) + throws IOException + { + FileInputStream fis = null; + try + { + fis = new FileInputStream( fileName ); + return streamToString( fis ); + } + finally + { + if( fis != null ) try { fis.close(); } catch( Exception any ) {} + } + } + //--------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------- +} Added: maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifier.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifier.java?rev=684996&view=auto ============================================================================== --- maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifier.java (added) +++ maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifier.java Mon Aug 11 17:08:39 2008 @@ -0,0 +1,210 @@ +package org.apache.maven.mercury.crypto.pgp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.NoSuchProviderException; +import java.security.SignatureException; + +import org.apache.maven.mercury.crypto.api.AbstractStreamVerifier; +import org.apache.maven.mercury.crypto.api.StreamObserverException; +import org.apache.maven.mercury.crypto.api.StreamVerifier; +import org.apache.maven.mercury.crypto.api.StreamVerifierAttributes; +import org.apache.maven.mercury.crypto.api.StreamVerifierException; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.openpgp.PGPCompressedData; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPUtil; +import org.codehaus.plexus.i18n.DefaultLanguage; +import org.codehaus.plexus.i18n.Language; +import org.codehaus.plexus.util.StringInputStream; + +/** + * lightweight pgp stream encoder, created one per stream + * + * @author Oleg Gusakov + * @version $Id$ + * + */ +public class PgpStreamVerifier +extends AbstractStreamVerifier +implements StreamVerifier +{ + public static final String TYPE = "pgp"; + private static final Language lang = new DefaultLanguage( PgpStreamVerifier.class ); + + private PGPPublicKeyRingCollection trustedPublicKeyRing; + + private PGPSignatureGenerator signatureGenerator; + + private PGPSignature signature; + + private String signatureString; + + //----------------------------------------------------------------------------------- + public PgpStreamVerifier( StreamVerifierAttributes attributes ) + { + super( attributes ); + } + //----------------------------------------------------------------------------------- + public void init( PGPPublicKeyRingCollection trustedPublicKeyRing ) + { + this.trustedPublicKeyRing = trustedPublicKeyRing; + } + //----------------------------------------------------------------------------------- + public void init( PGPPrivateKey privateKey, int algorithm, int digestAlgorithm ) + throws StreamVerifierException + { + if( privateKey == null ) + throw new IllegalArgumentException( lang.getMessage( "null.private.key" )); + + try + { + signatureGenerator = new PGPSignatureGenerator( algorithm + , digestAlgorithm + , PgpHelper.PROVIDER + ); + signatureGenerator.initSign( PGPSignature.BINARY_DOCUMENT, privateKey ); + + signatureString = null; + } + catch( Exception e ) + { + throw new StreamVerifierException(e); + } + } + + //----------------------------------------------------------------------------------- + public void byteReady( int b ) + throws StreamObserverException + { + try + { + if( signature == null ) + { + if( signatureGenerator == null ) + throw new StreamVerifierException( lang.getMessage( "no.stream.processor" ) ); + signatureGenerator.update( (byte)b ); + } + else + signature.update( (byte)b ); + } + catch( SignatureException e ) + { + throw new StreamObserverException(e); + } + } + + //----------------------------------------------------------------------------------- + public void bytesReady( byte[] b, int off, int len ) + throws StreamObserverException + { + try + { + if( signature == null ) + { + if( signatureGenerator == null ) + throw new StreamVerifierException( lang.getMessage( "no.stream.processor" ) ); + signatureGenerator.update( b, off, len ); + } + else + signature.update( b, off, len ); + } + catch( SignatureException e ) + { + throw new StreamObserverException(e); + } + } + //----------------------------------------------------------------------------------- + public void initSignature( String signatureString ) + throws StreamVerifierException + { + try + { + if( trustedPublicKeyRing == null ) + throw new StreamVerifierException( lang.getMessage( "no.trusted.ring" ) ); + + if( signatureString == null || signatureString.length() < 1 ) + throw new StreamVerifierException( lang.getMessage( "no.signature.string" ) ); + + signature = PgpHelper.readSignature( new ByteArrayInputStream( signatureString.getBytes() ) ); + + if( signature == null ) + throw new StreamVerifierException( "no.signatures.in.stream" ); + + signature.initVerify( trustedPublicKeyRing.getPublicKey( signature.getKeyID() ), PgpHelper.PROVIDER ); + } + catch( Exception e ) + { + throw new StreamVerifierException(e); + } + + if( signature == null ) + throw new StreamVerifierException("no.signatures.in.stream"); + + } + //----------------------------------------------------------------------------------- + public boolean verifySignature() + throws StreamVerifierException + { + + if( signature == null ) + throw new StreamVerifierException( lang.getMessage( "null.verify.signature" )); + + try + { + return signature.verify(); + } + catch( Exception e ) + { + throw new StreamVerifierException( e ); + } + } + + //----------------------------------------------------------------------------------- + public String getSignature() + throws StreamVerifierException + { + if( signatureString != null ) + return signatureString; + + if( signatureGenerator == null ) + throw new StreamVerifierException("bad.verify.signature.state"); + + BCPGOutputStream signaturePgpBytes = null; + try + { + ByteArrayOutputStream signatureBytes = new ByteArrayOutputStream(); + ArmoredOutputStream aos = new ArmoredOutputStream( signatureBytes ); + signaturePgpBytes = new BCPGOutputStream( aos ); + signatureGenerator.generate().encode( signaturePgpBytes ); + signaturePgpBytes.finish(); + aos.flush(); + aos.close(); + signatureString = signatureBytes.toString(); + } + catch( Exception e ) + { + throw new StreamVerifierException( e ); + } + finally + { + if( signaturePgpBytes != null ) try { signaturePgpBytes.close(); } catch( Exception any ) {} + } + + signatureGenerator = null; + + return signatureString; + } + //----------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------- +} Added: maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifierFactory.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifierFactory.java?rev=684996&view=auto ============================================================================== --- maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifierFactory.java (added) +++ maven/sandbox/trunk/mercury/mercury-crypto/mercury-crypto-basic/src/main/java/org/apache/maven/mercury/crypto/pgp/PgpStreamVerifierFactory.java Mon Aug 11 17:08:39 2008 @@ -0,0 +1,128 @@ +package org.apache.maven.mercury.crypto.pgp; + +import java.io.InputStream; + +import org.apache.maven.mercury.crypto.api.AbstractStreamVerifierFactory; +import org.apache.maven.mercury.crypto.api.StreamVerifier; +import org.apache.maven.mercury.crypto.api.StreamVerifierAttributes; +import org.apache.maven.mercury.crypto.api.StreamVerifierException; +import org.apache.maven.mercury.crypto.api.StreamVerifierFactory; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPUtil; +import org.codehaus.plexus.i18n.DefaultLanguage; +import org.codehaus.plexus.i18n.Language; + +/** + * + * + * @author Oleg Gusakov + * @version $Id$ + * + */ +public class PgpStreamVerifierFactory +extends AbstractStreamVerifierFactory +implements StreamVerifierFactory +{ + + public static final String DEFAULT_EXTENSION = PgpHelper.EXTENSION; + + private static final Language lang = new DefaultLanguage( PgpStreamVerifierFactory.class ); + + private PGPPublicKeyRingCollection trustedPublicKeyRing; + + private PGPPrivateKey privateKey; + + private int algorithm = 0; + + private int digestAlgorithm = PGPUtil.SHA1; + + //-------------------------------------------------------------------------------------------- + public PgpStreamVerifierFactory( StreamVerifierAttributes attributes + , InputStream trustedPublicKeyRingStream + ) + throws StreamVerifierException + { + super( attributes ); + init( trustedPublicKeyRingStream ); + + } + //-------------------------------------------------------------------------------------------- + public PgpStreamVerifierFactory( StreamVerifierAttributes attributes + , InputStream secretKeyRingStream + , String secretKeyId + , String secretKeyPass + ) + throws StreamVerifierException + { + super( attributes ); + init( secretKeyRingStream, secretKeyId, secretKeyPass ); + } + //-------------------------------------------------------------------------------------------- + public void init( InputStream trustedPublicKeyRingStream ) + throws StreamVerifierException + { + try + { + if( trustedPublicKeyRingStream != null ) + { + trustedPublicKeyRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(trustedPublicKeyRingStream)); + if( trustedPublicKeyRing == null ) + throw new StreamVerifierException( lang.getMessage( "bad.factory.init.verify.empty" ) ); + } + else + throw new StreamVerifierException( lang.getMessage( "bad.factory.init.verify" ) ); + } + catch( Exception e ) + { + throw new StreamVerifierException(e); + } + } + //-------------------------------------------------------------------------------------------- + public void init( InputStream secretKeyRingStream + , String secretKeyId + , String secretKeyPass + ) + throws StreamVerifierException + { + try + { + if( secretKeyRingStream != null && secretKeyId != null && secretKeyPass != null ) + { + PGPSecretKeyRing secRing = PgpHelper.readKeyRing( secretKeyRingStream, secretKeyId ); + PGPSecretKey secKey = secRing.getSecretKey( PgpHelper.hexToId( secretKeyId ) ); + privateKey = secKey.extractPrivateKey( secretKeyPass.toCharArray(), PgpHelper.PROVIDER ); + algorithm = secKey.getPublicKey().getAlgorithm(); + } + else + throw new StreamVerifierException( lang.getMessage( "bad.factory.init.generate" ) ); + } + catch( Exception e ) + { + throw new StreamVerifierException(e); + } + } + //-------------------------------------------------------------------------------------------- + public String getDefaultExtension() + { + return DEFAULT_EXTENSION; + } + //-------------------------------------------------------------------------------------------- + public StreamVerifier newInstance() + throws StreamVerifierException + { + PgpStreamVerifier sv = new PgpStreamVerifier( attributes ); + + if( privateKey != null ) + sv.init( privateKey, algorithm, digestAlgorithm ); + + if( trustedPublicKeyRing != null ) + sv.init( trustedPublicKeyRing ); + + return sv; + } + //-------------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------------- +}