[prev in list] [next in list] [prev in thread] [next in thread]
List: bouncycastle-crypto-dev
Subject: Re: [dev-crypto] Creating a Separate Signature File
From: David Hook <dgh () lockboxlabs ! com>
Date: 2008-06-25 3:58:21
Message-ID: 1214366301.3633.25.camel () echidna
[Download RAW message or body]
Yes, sign then encrypt, the motto is "always sign what you mean".
An example of this for PGP (which is what I'm assuming you are using)
was posted a while a go. I've attached it to the email as an example -
for some reason the original message didn't get archived. Basically it's
just a matter of replacing the code supporting the literal data object
with code supporting a signed one.
Regards,
David
On Tue, 2008-06-24 at 18:43 -0400, Mark Lookabaugh wrote:
> Hi,
>
> We have binary plaintext data which we would like to sign and
> encrypt.
>
> My understanding is that we should first sign the plaintext data
> creating a separate signature file, next encrypt the plaintext data,
> and finally forward the encrypted data and the signature file together
> to the recipient. Does that sound like the proper procedure?
>
> We have the encryption code in place already. What is the process to
> create a signature file that is separate from the item being signed?
>
> Thank you,
> Mark
>
["EncryptDecryptLargeFiles.java" (EncryptDecryptLargeFiles.java)]
package myTest;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
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.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
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.PGPPublicKeyEncryptedData;
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;
public class EncryptDecryptLargeFiles {
private static PGPPublicKey readPublicKey(
InputStream in)
throws IOException, PGPException
{
in = PGPUtil.getDecoderStream(in);
PGPPublicKeyRingCollection pgpPub = new \
PGPPublicKeyRingCollection(in);
//
// we just loop through the collection till we find a key suitable for \
encryption, in the real // world you would probably want to be a bit smarter about \
this. //
PGPPublicKey key = null;
//
// iterate through the key rings.
//
Iterator rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext())
{
PGPPublicKeyRing kRing = (PGPPublicKeyRing)rIt.next();
Iterator kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext())
{
PGPPublicKey k = (PGPPublicKey)kIt.next();
if (k.isEncryptionKey())
{
key = k;
}
}
}
if (key == null)
{
throw new IllegalArgumentException("Can't find encryption key in key \
ring."); }
return key;
}
private static PGPPrivateKey findSecretKey(
PGPSecretKeyRingCollection pgpSec,
long keyID,
char[] pass)
throws PGPException, NoSuchProviderException
{
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.extractPrivateKey(pass, "BC");
}
/**
* To Decrypt and then verify signature
*/
public static void decryptThenVerifySign(InputStream in, InputStream keyIn, char[] \
passwd, InputStream pubKeyIn) throws Exception{ in = PGPUtil.getDecoderStream(in);
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList)
{
enc = (PGPEncryptedDataList)o;
}
else
{
enc = (PGPEncryptedDataList)pgpF.nextObject();
}
//
// find the secret key
//
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new \
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn)); while (sKey == null && \
it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData)it.next();
sKey = findSecretKey(pgpSec, pbe.getKeyID(), passwd);
System.out.println("Secret Key ID : " + sKey.getKeyID());
}
if (sKey == null)
{
throw new IllegalArgumentException("secret key for message not found.");
}
// decrypt the data
InputStream clear = pbe.getDataStream(sKey, "BC");
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object message = plainFact.nextObject();
System.out.println("Object is " + message);
if (message instanceof PGPCompressedData)
{
System.out.println("Found instance of PGPCompressedData");
PGPCompressedData cData = (PGPCompressedData)message;
PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());
message = pgpFact.nextObject();
System.out.println("Object is " + message);
if (message instanceof PGPOnePassSignatureList)
{
System.out.println("Found instance of PGPOnePassSignatureList");
// verify the signature
PGPOnePassSignature ops = ((PGPOnePassSignatureList) message).get(0);
PGPPublicKeyRingCollection pgpRing = new \
PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(pubKeyIn));
PGPPublicKey key = \
pgpRing.getPublicKey(ops.getKeyID()); System.out.println("Public Key ID : " + \
key.getKeyID());
ops.initVerify(key, "BC");
message = pgpFact.nextObject();
if (message instanceof PGPLiteralData) {
System.out.println("Found instance of PGPLiteralData");
PGPLiteralData ld = (PGPLiteralData)message;
FileOutputStream fOut = new \
FileOutputStream("sample.txt.decrypt");
BufferedOutputStream bOut = new BufferedOutputStream(fOut);
/** use of buffering to speed up write **/
byte[] buffer = new byte[1<<16];
InputStream fIn = ld.getInputStream();
int bytesRead = 0;
while((bytesRead = fIn.read(buffer)) != -1) {
bOut.write(buffer,0,bytesRead);
ops.update(buffer,0,bytesRead);
}
bOut.close();
// verify the signature
if (ops != null) {
PGPSignatureList signatureList = (PGPSignatureList) \
pgpFact.nextObject();
System.out.println("signature list (" + signatureList.size() + " sigs) \
is " + signatureList);
PGPSignature messageSignature = (PGPSignature) signatureList.get(0);
System.out.println("verification signature is " + messageSignature);
if (!ops.verify(messageSignature)) {
throw new RuntimeException("signature verification failed");
}
else{
System.out.println(" *** Signature verification success *** ");
}
}
}// end of if PGPLiteralData
}// end of if PGPOnePassSignatureList
}
else{
System.err.println("PGPCompressedData not available!");
}
}
/**
* Method to sign-THEN-encrypt
*/
private static void signThenEncryptFile(
OutputStream out,
String fileName,
PGPPublicKey encKey,
boolean armor,
boolean withIntegrityCheck,
InputStream keyIn,
char[] pass)
throws IOException, NoSuchAlgorithmException, NoSuchProviderException, \
PGPException, SignatureException {
if (armor)
{
out = new ArmoredOutputStream(out);
}
try
{
PGPEncryptedDataGenerator cPk = new \
PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, withIntegrityCheck, new \
SecureRandom(), "BC"); cPk.addMethod(encKey);
OutputStream cOut = cPk.open(out, new byte[1 << 16]);
//PGPCompressedDataGenerator comData = new \
PGPCompressedDataGenerator(PGPCompressedData.ZIP);
//PGPUtil.writeFileToLiteralData(comData.open(cOut), \
PGPLiteralData.BINARY, new File(fileName), new byte[1 << 16]);
///// instead of the above two commented line include the code from \
SignedFileProcessor.java PGPSecretKey pgpSec = readSecretKey(keyIn);
PGPPrivateKey pgpPrivKey = \
pgpSec.extractPrivateKey(pass, "BC");
PGPSignatureGenerator sGen = new \
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1, "BC");
sGen.initSign(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext())
{
PGPSignatureSubpacketGenerator spGen = new \
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String)it.next());
sGen.setHashedSubpackets(spGen.generate());
}
PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(
\
PGPCompressedData.ZLIB);
BCPGOutputStream bOut = new \
BCPGOutputStream(cGen.open(cOut)); sGen.generateOnePassVersion(false).encode(bOut);
File file = new File(fileName);
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
OutputStream lOut = lGen.open(bOut, \
PGPLiteralData.BINARY, file.getName(), new Date(),new byte[1<<16]); // use of \
buffering to speed up write byte[] buffer = new byte[1<<16];
FileInputStream fIn = new FileInputStream(file);
int bytesRead = 0;
while((bytesRead = fIn.read(buffer)) != -1) {
lOut.write(buffer,0,bytesRead);
sGen.update(buffer,0,bytesRead);
lOut.flush();
}
lGen.close();
sGen.generate().encode(bOut);
cGen.close();
/////end of sign
//comData.close();
cOut.close();
out.close();
}
catch (PGPException e)
{
System.err.println(e);
if (e.getUnderlyingException() != null)
{
e.getUnderlyingException().printStackTrace();
}
}
}
/**
* A simple routine that opens a key ring file and loads the first available key \
suitable for
* signature generation.
*
* @param in
* @return
* @throws IOException
* @throws PGPException
*/
private static PGPSecretKey readSecretKey(
InputStream in)
throws IOException, PGPException
{
in = PGPUtil.getDecoderStream(in);
PGPSecretKeyRingCollection pgpSec = new \
PGPSecretKeyRingCollection(in);
//
// we just loop through the collection till we find a key suitable for \
encryption, in the real // world you would probably want to be a bit smarter about \
this. //
PGPSecretKey key = null;
//
// iterate through the key rings.
//
Iterator rIt = pgpSec.getKeyRings();
while (key == null && rIt.hasNext())
{
PGPSecretKeyRing kRing = (PGPSecretKeyRing)rIt.next();
Iterator kIt = kRing.getSecretKeys();
while (key == null && kIt.hasNext())
{
PGPSecretKey k = (PGPSecretKey)kIt.next();
if (k.isSigningKey())
{
key = k;
}
}
}
if (key == null)
{
throw new IllegalArgumentException("Can't find signing key in key \
ring."); }
return key;
}
private static String inputFileName = "sample.txt";
private static String outputFileName = inputFileName + ".asc";
static String publicKeyFilePath = \
"C:/CustomerProjects/PGP/Testing/Source/conf/pubring.pkr"; static String \
privateKeyFilePath = "C:/CustomerProjects/PGP/Testing/Source/conf/secring.skr";
static String password = "abc";
/**
* @param args
*/
public static void main(String[] args) throws Exception{
Security.addProvider(new BouncyCastleProvider());
System.out.println(">>> This is test for LARGE files");
// to test digitally signing/verifying LARGE files
System.out.println(">>> START - sign-THEN-encrypt");
// public key
FileInputStream publicKeyIn = new FileInputStream(publicKeyFilePath);
// private key
FileInputStream privKeyIn = new FileInputStream(privateKeyFilePath);
// output file name (sample.txt.asc)
FileOutputStream fOut = new FileOutputStream(outputFileName);
// sign-THEN-encrypt
signThenEncryptFile(fOut, inputFileName, readPublicKey(publicKeyIn), true, true, \
privKeyIn, password.toCharArray()); System.out.println(">>> END - \
sign-THEN-encrypt");
System.out.println(">>> START - decrypt-THEN-verify");
// encrypted file name (sample.txt.asc)
FileInputStream fin1 = new FileInputStream(outputFileName);
// private key
FileInputStream fprivate1= new FileInputStream(privateKeyFilePath);
// public key
FileInputStream fpublic1 = new FileInputStream(publicKeyFilePath);
// decrypt-THEN-verify
decryptThenVerifySign(fin1, fprivate1, password.toCharArray(),fpublic1);
System.out.println(">>> END - decrypt-THEN-verify");
}
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic