Discussion:
BouncyCastle PGP and McAfee eBusiness Server 8.6 Incompatibility
Caine Lai
2011-07-08 00:21:07 UTC
Permalink
I have been banging my head against the wall now for a couple of weeks
trying to figure out why our bank cannot decrypt a message that has been
single-pass signed and encrypted using BouncyCastle PGP. The bank is using
McAfee E-Business Server 8.6 for decryption.

The data is encrypted with the bank's public key, and is signed with our
private key.

Using our own public key for encryption, I am successfully able to decrypt
and verify the signature on a file generated with the code below. Gnupg can
decrypt and verify the file just fine.

However, the bank is unable to decrypt the file. I have tried first turning
compression off, and then turning ASCII armoring off. Neither option seems
to work, and they always get the same error message no matter what options I
try:

event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
Key for user ID "XXXXXXXXX <***@XXXX>"
event 6: Passphrase
event 23: Decryption

symmetric cipher used: CAST5
event 3: error -11391

event 2: final

Error decrypting file '/somepath/FILENAME'.
Corrupt data.
Bad packet

exitcode = 32

Here is the code I am using to do the single pass sign and encrypt:

public class PGPService {

private static final Logger log = Logger.getLogger(PGPService.class);


static {
Security.addProvider(new BouncyCastleProvider());
}


/**
* A simple routine that opens a key ring file and loads the first
available key
* suitable for signature generation.
*
* @param input stream to read the secret key ring collection from.
* @return a secret key.
* @throws IOException on a problem with using the input stream.
* @throws PGPException if there is an issue parsing the input stream.
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey readSecretKey(InputStream input) throws
IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));

// 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.

Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}

throw new IllegalArgumentException("Can't find signing key in key
ring.");
}

/**
* Single pass signs and encrypts the given file to the given output
file using the provided keys.
*
* @param fileNameIn - The name and location of the source input file.
* @param fileNameOut - The name and location of the destination output
file.
* @param privateKeyIn - The input stream for the private key file.
* @param privateKeyPassword - The password for the private key file.
* @param publicEncryptionKey - The public encryption key.
* @param armoredOutput - Whether or not to ASCII armor the output.
*/
@SuppressWarnings("rawtypes")
public static void signAndEncrypt(String fileNameIn, String fileNameOut,
InputStream privateKeyIn, String privateKeyPassword, PGPPublicKey
publicEncryptionKey, boolean armoredOutput, boolean compress) {

int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut = null;
OutputStream literalOut = null;
PGPEncryptedDataGenerator encryptedDataGenerator = null;
PGPCompressedDataGenerator compressedDataGenerator = null;
PGPSignatureGenerator signatureGenerator = null;
PGPLiteralDataGenerator literalDataGenerator = null;

try {

File output = new File(fileNameOut);
OutputStream out = new FileOutputStream(output);
if (armoredOutput) out = new ArmoredOutputStream(out);

// ? Use BCPGOutputStreams ?

// Init encrypted data generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, true, new
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
finalOut = new BufferedOutputStream(out, bufferSize);
encOut = encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);

// Init compression
if (compress) {
compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
}

// Init signature
PGPSecretKey pgpSec = readSecretKey(privateKeyIn);
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(), "BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1,
"BC");

signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
pgpPrivKey);
Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
}
PGPOnePassSignature onePassSignature =
signatureGenerator.generateOnePassVersion(false);
if (compress) onePassSignature.encode(compressedOut);
else onePassSignature.encode(encOut);

// Create the Literal Data generator Output stream which writes
to the compression stream
literalDataGenerator = new PGPLiteralDataGenerator(true);
if (compress) literalOut =
literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY,
output.getName(), new Date(), new byte[bufferSize]);
else literalOut = literalDataGenerator.open(encOut,
PGPLiteralData.TEXT, fileNameIn, new Date(), new byte[bufferSize]);

// Update sign and encrypt
byte[] buffer = new byte[bufferSize];

int bytesRead = 0;
input = new FileInputStream(fileNameIn);
while((bytesRead = input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
literalOut.flush();
}

// Close Literal data stream and add signature
literalOut.close();
literalDataGenerator.close();
if (compress)
signatureGenerator.generate().encode(compressedOut);
else signatureGenerator.generate().encode(encOut);

} catch (Exception e) {
log.error(e);
throw new RuntimeException(e);
} finally {
// Close all streams
if (literalOut != null) try { literalOut.close(); } catch
(IOException e) {}
if (literalDataGenerator != null) try {
literalDataGenerator.close(); } catch (IOException e) {}
if (compressedOut != null) try { compressedOut.close(); } catch
(IOException e) {}
if (compressedDataGenerator != null) try {
compressedDataGenerator.close(); } catch (IOException e) {}
if (encOut != null) try { encOut.close(); } catch (IOException
e) {}
if (encryptedDataGenerator != null) try {
encryptedDataGenerator.close(); } catch (IOException e) {}
if (finalOut != null) try { finalOut.close(); } catch
(IOException e) {}
if (input != null) try { input.close(); } catch (IOException e)
{}
}
}

@SuppressWarnings("rawtypes")
private static PGPPublicKey readPublicKeyFromCol(InputStream in) throws
Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " + pkCol.size());
Iterator it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing) it.next();
Iterator pkIt = pkRing.getPublicKeys();
while (pkIt.hasNext()) {
PGPPublicKey key = (PGPPublicKey) pkIt.next();
log.info("Encryption key = " + key.isEncryptionKey() + ",
Master key = " +
key.isMasterKey());
if (key.isEncryptionKey()) {
// Find out a little about the keys in the public key
ring.
log.info("Key Strength = " + key.getBitStrength());
log.info("Algorithm = " + key.getAlgorithm());
log.info("Bit strength = " + key.getBitStrength());
log.info("Version = " + key.getVersion());
return key;
}
}
}
return null;
}

private static PGPPrivateKey findSecretKey(InputStream keyIn, long
keyID, char[] pass)
throws IOException, PGPException, NoSuchProviderException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass, "BC");
}
}

Any idea what could be causing this? I've found numerous reports using
Google, but no resolutions or follow-ups.
David Hook
2011-07-08 00:40:10 UTC
Permalink
Have you tried not using packet mode?

Regards,

David
Post by Caine Lai
I have been banging my head against the wall now for a couple of weeks
trying to figure out why our bank cannot decrypt a message that has
been single-pass signed and encrypted using BouncyCastle PGP. The bank
is using McAfee E-Business Server 8.6 for decryption.
The data is encrypted with the bank's public key, and is signed with
our private key.
Using our own public key for encryption, I am successfully able to
decrypt and verify the signature on a file generated with the code
below. Gnupg can decrypt and verify the file just fine.
However, the bank is unable to decrypt the file. I have tried first
turning compression off, and then turning ASCII armoring off. Neither
option seems to work, and they always get the same error message no
event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file '/somepath/FILENAME'.
Corrupt data.
Bad packet
exitcode = 32
public class PGPService {
private static final Logger log =
Logger.getLogger(PGPService.class);
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* A simple routine that opens a key ring file and loads the first
available key
* suitable for signature generation.
*
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey readSecretKey(InputStream input)
throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
// 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.
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in
key ring.");
}
/**
* Single pass signs and encrypts the given file to the given
output file using the provided keys.
*
output file.
*/
@SuppressWarnings("rawtypes")
public static void signAndEncrypt(String fileNameIn, String
fileNameOut, InputStream privateKeyIn, String privateKeyPassword,
PGPPublicKey publicEncryptionKey, boolean armoredOutput, boolean
compress) {
int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut = null;
OutputStream literalOut = null;
PGPEncryptedDataGenerator encryptedDataGenerator = null;
PGPCompressedDataGenerator compressedDataGenerator = null;
PGPSignatureGenerator signatureGenerator = null;
PGPLiteralDataGenerator literalDataGenerator = null;
try {
File output = new File(fileNameOut);
OutputStream out = new FileOutputStream(output);
if (armoredOutput) out = new ArmoredOutputStream(out);
// ? Use BCPGOutputStreams ?
// Init encrypted data generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, true, new
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
finalOut = new BufferedOutputStream(out, bufferSize);
encOut = encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);
// Init compression
if (compress) {
compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
}
// Init signature
PGPSecretKey pgpSec = readSecretKey(privateKeyIn);
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(),
"BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
pgpPrivKey);
Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
}
PGPOnePassSignature onePassSignature =
signatureGenerator.generateOnePassVersion(false);
if (compress) onePassSignature.encode(compressedOut);
else onePassSignature.encode(encOut);
// Create the Literal Data generator Output stream which
writes to the compression stream
literalDataGenerator = new PGPLiteralDataGenerator(true);
if (compress) literalOut =
literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY,
output.getName(), new Date(), new byte[bufferSize]);
else literalOut = literalDataGenerator.open(encOut,
PGPLiteralData.TEXT, fileNameIn, new Date(), new byte[bufferSize]);
// Update sign and encrypt
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
input = new FileInputStream(fileNameIn);
while((bytesRead = input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
literalOut.flush();
}
// Close Literal data stream and add signature
literalOut.close();
literalDataGenerator.close();
if (compress)
signatureGenerator.generate().encode(compressedOut);
else signatureGenerator.generate().encode(encOut);
} catch (Exception e) {
log.error(e);
throw new RuntimeException(e);
} finally {
// Close all streams
if (literalOut != null) try { literalOut.close(); } catch
(IOException e) {}
if (literalDataGenerator != null) try
{ literalDataGenerator.close(); } catch (IOException e) {}
if (compressedOut != null) try { compressedOut.close(); }
catch (IOException e) {}
if (compressedDataGenerator != null) try {
compressedDataGenerator.close(); } catch (IOException e) {}
if (encOut != null) try { encOut.close(); } catch
(IOException e) {}
if (encryptedDataGenerator != null) try {
encryptedDataGenerator.close(); } catch (IOException e) {}
if (finalOut != null) try { finalOut.close(); } catch
(IOException e) {}
if (input != null) try { input.close(); } catch
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
private static PGPPublicKey readPublicKeyFromCol(InputStream in)
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " + pkCol.size());
Iterator it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing) it.next();
Iterator pkIt = pkRing.getPublicKeys();
while (pkIt.hasNext()) {
PGPPublicKey key = (PGPPublicKey) pkIt.next();
log.info("Encryption key = " + key.isEncryptionKey() +
", Master key = " +
key.isMasterKey());
if (key.isEncryptionKey()) {
// Find out a little about the keys in the public
key ring.
log.info("Key Strength = " +
key.getBitStrength());
log.info("Algorithm = " + key.getAlgorithm());
log.info("Bit strength = " +
key.getBitStrength());
log.info("Version = " + key.getVersion());
return key;
}
}
}
return null;
}
private static PGPPrivateKey findSecretKey(InputStream keyIn, long
keyID, char[] pass)
throws IOException, PGPException, NoSuchProviderException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass, "BC");
}
}
Any idea what could be causing this? I've found numerous reports using
Google, but no resolutions or follow-ups.
Caine Lai
2011-07-08 00:51:03 UTC
Permalink
No, I would have no idea how to go about doing that. Do you mean removing
the PGPSignatureSubpacketGenerator? I based the code on the
SignedFileProcessor in the Bouncy Castle examples. Is there another way to
do single pass sign and encrypt?

Thanks,
Caine
Post by David Hook
Have you tried not using packet mode?
Regards,
David
Post by Caine Lai
I have been banging my head against the wall now for a couple of weeks
trying to figure out why our bank cannot decrypt a message that has
been single-pass signed and encrypted using BouncyCastle PGP. The bank
is using McAfee E-Business Server 8.6 for decryption.
The data is encrypted with the bank's public key, and is signed with
our private key.
Using our own public key for encryption, I am successfully able to
decrypt and verify the signature on a file generated with the code
below. Gnupg can decrypt and verify the file just fine.
However, the bank is unable to decrypt the file. I have tried first
turning compression off, and then turning ASCII armoring off. Neither
option seems to work, and they always get the same error message no
event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file '/somepath/FILENAME'.
Corrupt data.
Bad packet
exitcode = 32
public class PGPService {
private static final Logger log =
Logger.getLogger(PGPService.class);
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* A simple routine that opens a key ring file and loads the first
available key
* suitable for signature generation.
*
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey readSecretKey(InputStream input)
throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
// 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.
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in
key ring.");
}
/**
* Single pass signs and encrypts the given file to the given
output file using the provided keys.
*
output file.
*/
@SuppressWarnings("rawtypes")
public static void signAndEncrypt(String fileNameIn, String
fileNameOut, InputStream privateKeyIn, String privateKeyPassword,
PGPPublicKey publicEncryptionKey, boolean armoredOutput, boolean
compress) {
int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut = null;
OutputStream literalOut = null;
PGPEncryptedDataGenerator encryptedDataGenerator = null;
PGPCompressedDataGenerator compressedDataGenerator = null;
PGPSignatureGenerator signatureGenerator = null;
PGPLiteralDataGenerator literalDataGenerator = null;
try {
File output = new File(fileNameOut);
OutputStream out = new FileOutputStream(output);
if (armoredOutput) out = new ArmoredOutputStream(out);
// ? Use BCPGOutputStreams ?
// Init encrypted data generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, true, new
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
finalOut = new BufferedOutputStream(out, bufferSize);
encOut = encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);
// Init compression
if (compress) {
compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
}
// Init signature
PGPSecretKey pgpSec = readSecretKey(privateKeyIn);
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(),
"BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
pgpPrivKey);
Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
}
PGPOnePassSignature onePassSignature =
signatureGenerator.generateOnePassVersion(false);
if (compress) onePassSignature.encode(compressedOut);
else onePassSignature.encode(encOut);
// Create the Literal Data generator Output stream which
writes to the compression stream
literalDataGenerator = new PGPLiteralDataGenerator(true);
if (compress) literalOut =
literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY,
output.getName(), new Date(), new byte[bufferSize]);
else literalOut = literalDataGenerator.open(encOut,
PGPLiteralData.TEXT, fileNameIn, new Date(), new byte[bufferSize]);
// Update sign and encrypt
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
input = new FileInputStream(fileNameIn);
while((bytesRead = input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
literalOut.flush();
}
// Close Literal data stream and add signature
literalOut.close();
literalDataGenerator.close();
if (compress)
signatureGenerator.generate().encode(compressedOut);
else signatureGenerator.generate().encode(encOut);
} catch (Exception e) {
log.error(e);
throw new RuntimeException(e);
} finally {
// Close all streams
if (literalOut != null) try { literalOut.close(); } catch
(IOException e) {}
if (literalDataGenerator != null) try
{ literalDataGenerator.close(); } catch (IOException e) {}
if (compressedOut != null) try { compressedOut.close(); }
catch (IOException e) {}
if (compressedDataGenerator != null) try {
compressedDataGenerator.close(); } catch (IOException e) {}
if (encOut != null) try { encOut.close(); } catch
(IOException e) {}
if (encryptedDataGenerator != null) try {
encryptedDataGenerator.close(); } catch (IOException e) {}
if (finalOut != null) try { finalOut.close(); } catch
(IOException e) {}
if (input != null) try { input.close(); } catch
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
private static PGPPublicKey readPublicKeyFromCol(InputStream in)
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " + pkCol.size());
Iterator it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing) it.next();
Iterator pkIt = pkRing.getPublicKeys();
while (pkIt.hasNext()) {
PGPPublicKey key = (PGPPublicKey) pkIt.next();
log.info("Encryption key = " + key.isEncryptionKey() +
", Master key = " +
key.isMasterKey());
if (key.isEncryptionKey()) {
// Find out a little about the keys in the public
key ring.
log.info("Key Strength = " +
key.getBitStrength());
log.info("Algorithm = " + key.getAlgorithm());
log.info("Bit strength = " +
key.getBitStrength());
log.info("Version = " + key.getVersion());
return key;
}
}
}
return null;
}
private static PGPPrivateKey findSecretKey(InputStream keyIn, long
keyID, char[] pass)
throws IOException, PGPException, NoSuchProviderException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass, "BC");
}
}
Any idea what could be causing this? I've found numerous reports using
Google, but no resolutions or follow-ups.
David Hook
2011-07-08 01:05:05 UTC
Permalink
Packet mode is on because you're passing byte arrays to some of the open
calls, as in:

encOut = encryptedDataGenerator.open(finalOut, new byte[bufferSize]);

There's a chance (surprisingly high unfortunately...) that the other end
will either not support it, or support it badly.

It'll mean you'll have to process the data in two passes which is a
hassle, but it's nowhere near as large a problem as it being unreadable.

Regards,

David
Post by Caine Lai
No, I would have no idea how to go about doing that. Do you mean
removing the PGPSignatureSubpacketGenerator? I based the code on the
SignedFileProcessor in the Bouncy Castle examples. Is there another
way to do single pass sign and encrypt?
Thanks,
Caine
Have you tried not using packet mode?
Regards,
David
Post by Caine Lai
I have been banging my head against the wall now for a
couple of weeks
Post by Caine Lai
trying to figure out why our bank cannot decrypt a message
that has
Post by Caine Lai
been single-pass signed and encrypted using BouncyCastle
PGP. The bank
Post by Caine Lai
is using McAfee E-Business Server 8.6 for decryption.
The data is encrypted with the bank's public key, and is
signed with
Post by Caine Lai
our private key.
Using our own public key for encryption, I am successfully
able to
Post by Caine Lai
decrypt and verify the signature on a file generated with
the code
Post by Caine Lai
below. Gnupg can decrypt and verify the file just fine.
However, the bank is unable to decrypt the file. I have
tried first
Post by Caine Lai
turning compression off, and then turning ASCII armoring
off. Neither
Post by Caine Lai
option seems to work, and they always get the same error
message no
Post by Caine Lai
event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file '/somepath/FILENAME'.
Corrupt data.
Bad packet
exitcode = 32
Here is the code I am using to do the single pass sign and
public class PGPService {
private static final Logger log =
Logger.getLogger(PGPService.class);
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* A simple routine that opens a key ring file and loads
the first
Post by Caine Lai
available key
* suitable for signature generation.
*
collection
Post by Caine Lai
from.
stream.
input
Post by Caine Lai
stream.
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey readSecretKey(InputStream
input)
Post by Caine Lai
throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
// We just loop through the collection till we find
a key
Post by Caine Lai
suitable for encryption, in the real
// world you would probably want to be a bit smarter
about
Post by Caine Lai
this.
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key =
(PGPSecretKey)keyIter.next();
Post by Caine Lai
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find
signing key in
Post by Caine Lai
key ring.");
}
/**
* Single pass signs and encrypts the given file to the
given
Post by Caine Lai
output file using the provided keys.
*
source input
Post by Caine Lai
file.
destination
Post by Caine Lai
output file.
private key
Post by Caine Lai
file.
private key
Post by Caine Lai
file.
key.
the
Post by Caine Lai
output.
*/
@SuppressWarnings("rawtypes")
public static void signAndEncrypt(String fileNameIn,
String
Post by Caine Lai
fileNameOut, InputStream privateKeyIn, String
privateKeyPassword,
Post by Caine Lai
PGPPublicKey publicEncryptionKey, boolean armoredOutput,
boolean
Post by Caine Lai
compress) {
int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut = null;
OutputStream literalOut = null;
PGPEncryptedDataGenerator encryptedDataGenerator =
null;
Post by Caine Lai
PGPCompressedDataGenerator compressedDataGenerator =
null;
Post by Caine Lai
PGPSignatureGenerator signatureGenerator = null;
PGPLiteralDataGenerator literalDataGenerator = null;
try {
File output = new File(fileNameOut);
OutputStream out = new FileOutputStream(output);
if (armoredOutput) out = new
ArmoredOutputStream(out);
Post by Caine Lai
// ? Use BCPGOutputStreams ?
// Init encrypted data generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5,
true, new
Post by Caine Lai
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
Post by Caine Lai
finalOut = new BufferedOutputStream(out,
bufferSize);
Post by Caine Lai
encOut = encryptedDataGenerator.open(finalOut,
new
Post by Caine Lai
byte[bufferSize]);
// Init compression
if (compress) {
compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
}
// Init signature
PGPSecretKey pgpSec =
readSecretKey(privateKeyIn);
Post by Caine Lai
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(), "BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
Post by Caine Lai
pgpPrivKey);
Iterator it =
pgpSec.getPublicKey().getUserIDs();
Post by Caine Lai
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false,
(String)it.next());
Post by Caine Lai
signatureGenerator.setHashedSubpackets(spGen.generate());
}
PGPOnePassSignature onePassSignature =
signatureGenerator.generateOnePassVersion(false);
if (compress)
onePassSignature.encode(compressedOut);
Post by Caine Lai
else onePassSignature.encode(encOut);
// Create the Literal Data generator Output
stream which
Post by Caine Lai
writes to the compression stream
literalDataGenerator = new
PGPLiteralDataGenerator(true);
Post by Caine Lai
if (compress) literalOut =
literalDataGenerator.open(compressedOut,
PGPLiteralData.BINARY,
Post by Caine Lai
output.getName(), new Date(), new byte[bufferSize]);
else literalOut =
literalDataGenerator.open(encOut,
Post by Caine Lai
PGPLiteralData.TEXT, fileNameIn, new Date(), new
byte[bufferSize]);
Post by Caine Lai
// Update sign and encrypt
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
input = new FileInputStream(fileNameIn);
while((bytesRead = input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
Post by Caine Lai
literalOut.flush();
}
// Close Literal data stream and add signature
literalOut.close();
literalDataGenerator.close();
if (compress)
signatureGenerator.generate().encode(compressedOut);
else
signatureGenerator.generate().encode(encOut);
Post by Caine Lai
} catch (Exception e) {
log.error(e);
throw new RuntimeException(e);
} finally {
// Close all streams
if (literalOut != null) try
{ literalOut.close(); } catch
Post by Caine Lai
(IOException e) {}
if (literalDataGenerator != null) try
{ literalDataGenerator.close(); } catch (IOException e) {}
if (compressedOut != null) try
{ compressedOut.close(); }
Post by Caine Lai
catch (IOException e) {}
if (compressedDataGenerator != null) try {
compressedDataGenerator.close(); } catch (IOException e) {}
if (encOut != null) try { encOut.close(); }
catch
Post by Caine Lai
(IOException e) {}
if (encryptedDataGenerator != null) try {
encryptedDataGenerator.close(); } catch (IOException e) {}
if (finalOut != null) try { finalOut.close(); }
catch
Post by Caine Lai
(IOException e) {}
if (input != null) try { input.close(); } catch
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
private static PGPPublicKey
readPublicKeyFromCol(InputStream in)
Post by Caine Lai
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " + pkCol.size());
Iterator it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing) it.next();
Iterator pkIt = pkRing.getPublicKeys();
while (pkIt.hasNext()) {
PGPPublicKey key = (PGPPublicKey)
pkIt.next();
Post by Caine Lai
log.info("Encryption key = " +
key.isEncryptionKey() +
Post by Caine Lai
", Master key = " +
key.isMasterKey());
if (key.isEncryptionKey()) {
// Find out a little about the keys in
the public
Post by Caine Lai
key ring.
log.info("Key Strength = " +
key.getBitStrength());
log.info("Algorithm = " +
key.getAlgorithm());
Post by Caine Lai
log.info("Bit strength = " +
key.getBitStrength());
log.info("Version = " +
key.getVersion());
Post by Caine Lai
return key;
}
}
}
return null;
}
private static PGPPrivateKey findSecretKey(InputStream
keyIn, long
Post by Caine Lai
keyID, char[] pass)
throws IOException, PGPException,
NoSuchProviderException
Post by Caine Lai
{
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass, "BC");
}
}
Any idea what could be causing this? I've found numerous
reports using
Post by Caine Lai
Google, but no resolutions or follow-ups.
David Hook
2011-07-08 01:29:17 UTC
Permalink
Yep.

By single step sign and encrypt they probably mean they want the signed
data inside the encrypted data - you'll need to do two passes as you'll
need to know the exact length of the signed data before you can encrypt
it. Of course if you're the one reading the message, rather than
creating it, this isn't a problem (as in the length is already there).
Or put another way, it'll still be one pass for them.

Regards,

David
Thanks for the reply David.
By process the data in two passes, do you mean sign the file first and
then encrypt the file in a second pass? I've been told by the bank
that they need single-step sign and encrypt.
I've no idea how doing it in two steps would affect the final data
though.
Thanks,
Caine
Packet mode is on because you're passing byte arrays to some of the open
encOut = encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);
There's a chance (surprisingly high unfortunately...) that the other end
will either not support it, or support it badly.
It'll mean you'll have to process the data in two passes which is a
hassle, but it's nowhere near as large a problem as it being unreadable.
Regards,
David
Post by Caine Lai
No, I would have no idea how to go about doing that. Do you
mean
Post by Caine Lai
removing the PGPSignatureSubpacketGenerator? I based the
code on the
Post by Caine Lai
SignedFileProcessor in the Bouncy Castle examples. Is there
another
Post by Caine Lai
way to do single pass sign and encrypt?
Thanks,
Caine
On Thu, Jul 7, 2011 at 5:40 PM, David Hook
Have you tried not using packet mode?
Regards,
David
Post by Caine Lai
I have been banging my head against the wall now
for a
Post by Caine Lai
couple of weeks
Post by Caine Lai
trying to figure out why our bank cannot decrypt a
message
Post by Caine Lai
that has
Post by Caine Lai
been single-pass signed and encrypted using
BouncyCastle
Post by Caine Lai
PGP. The bank
Post by Caine Lai
is using McAfee E-Business Server 8.6 for
decryption.
Post by Caine Lai
Post by Caine Lai
The data is encrypted with the bank's public key,
and is
Post by Caine Lai
signed with
Post by Caine Lai
our private key.
Using our own public key for encryption, I am
successfully
Post by Caine Lai
able to
Post by Caine Lai
decrypt and verify the signature on a file
generated with
Post by Caine Lai
the code
Post by Caine Lai
below. Gnupg can decrypt and verify the file just
fine.
Post by Caine Lai
Post by Caine Lai
However, the bank is unable to decrypt the file. I
have
Post by Caine Lai
tried first
Post by Caine Lai
turning compression off, and then turning ASCII
armoring
Post by Caine Lai
off. Neither
Post by Caine Lai
option seems to work, and they always get the same
error
Post by Caine Lai
message no
Post by Caine Lai
event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file '/somepath/FILENAME'.
Corrupt data.
Bad packet
exitcode = 32
Here is the code I am using to do the single pass
sign and
Post by Caine Lai
Post by Caine Lai
public class PGPService {
private static final Logger log =
Logger.getLogger(PGPService.class);
static {
Security.addProvider(new
BouncyCastleProvider());
Post by Caine Lai
Post by Caine Lai
}
/**
* A simple routine that opens a key ring file
and loads
Post by Caine Lai
the first
Post by Caine Lai
available key
* suitable for signature generation.
*
ring
Post by Caine Lai
collection
Post by Caine Lai
from.
the input
Post by Caine Lai
stream.
parsing the
Post by Caine Lai
input
Post by Caine Lai
stream.
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey
readSecretKey(InputStream
Post by Caine Lai
input)
Post by Caine Lai
throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
// We just loop through the collection
till we find
Post by Caine Lai
a key
Post by Caine Lai
suitable for encryption, in the real
// world you would probably want to be a
bit smarter
Post by Caine Lai
about
Post by Caine Lai
this.
Iterator keyRingIter =
pgpSec.getKeyRings();
Post by Caine Lai
Post by Caine Lai
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter =
keyRing.getSecretKeys();
Post by Caine Lai
Post by Caine Lai
while (keyIter.hasNext()) {
PGPSecretKey key =
(PGPSecretKey)keyIter.next();
Post by Caine Lai
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't
find
Post by Caine Lai
signing key in
Post by Caine Lai
key ring.");
}
/**
* Single pass signs and encrypts the given
file to the
Post by Caine Lai
given
Post by Caine Lai
output file using the provided keys.
*
of the
Post by Caine Lai
source input
Post by Caine Lai
file.
of the
Post by Caine Lai
destination
Post by Caine Lai
output file.
the
Post by Caine Lai
private key
Post by Caine Lai
file.
for the
Post by Caine Lai
private key
Post by Caine Lai
file.
encryption
Post by Caine Lai
key.
ASCII armor
Post by Caine Lai
the
Post by Caine Lai
output.
*/
@SuppressWarnings("rawtypes")
public static void signAndEncrypt(String
fileNameIn,
Post by Caine Lai
String
Post by Caine Lai
fileNameOut, InputStream privateKeyIn, String
privateKeyPassword,
Post by Caine Lai
PGPPublicKey publicEncryptionKey, boolean
armoredOutput,
Post by Caine Lai
boolean
Post by Caine Lai
compress) {
int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut = null;
OutputStream literalOut = null;
PGPEncryptedDataGenerator
encryptedDataGenerator =
Post by Caine Lai
null;
Post by Caine Lai
PGPCompressedDataGenerator
compressedDataGenerator =
Post by Caine Lai
null;
Post by Caine Lai
PGPSignatureGenerator signatureGenerator =
null;
Post by Caine Lai
Post by Caine Lai
PGPLiteralDataGenerator
literalDataGenerator = null;
Post by Caine Lai
Post by Caine Lai
try {
File output = new File(fileNameOut);
OutputStream out = new
FileOutputStream(output);
Post by Caine Lai
Post by Caine Lai
if (armoredOutput) out = new
ArmoredOutputStream(out);
Post by Caine Lai
// ? Use BCPGOutputStreams ?
// Init encrypted data generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5,
Post by Caine Lai
true, new
Post by Caine Lai
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
Post by Caine Lai
Post by Caine Lai
finalOut = new
BufferedOutputStream(out,
Post by Caine Lai
bufferSize);
Post by Caine Lai
encOut =
encryptedDataGenerator.open(finalOut,
Post by Caine Lai
new
Post by Caine Lai
byte[bufferSize]);
// Init compression
if (compress) {
compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
Post by Caine Lai
Post by Caine Lai
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
Post by Caine Lai
Post by Caine Lai
}
// Init signature
PGPSecretKey pgpSec =
readSecretKey(privateKeyIn);
Post by Caine Lai
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(),
Post by Caine Lai
Post by Caine Lai
"BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
Post by Caine Lai
Post by Caine Lai
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
Post by Caine Lai
Post by Caine Lai
pgpPrivKey);
Iterator it =
pgpSec.getPublicKey().getUserIDs();
Post by Caine Lai
if (it.hasNext()) {
PGPSignatureSubpacketGenerator
spGen = new
Post by Caine Lai
Post by Caine Lai
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false,
(String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
Post by Caine Lai
Post by Caine Lai
}
PGPOnePassSignature onePassSignature =
signatureGenerator.generateOnePassVersion(false);
if (compress)
onePassSignature.encode(compressedOut);
Post by Caine Lai
else onePassSignature.encode(encOut);
// Create the Literal Data generator
Output
Post by Caine Lai
stream which
Post by Caine Lai
writes to the compression stream
literalDataGenerator = new
PGPLiteralDataGenerator(true);
Post by Caine Lai
if (compress) literalOut =
literalDataGenerator.open(compressedOut,
PGPLiteralData.BINARY,
Post by Caine Lai
output.getName(), new Date(), new
byte[bufferSize]);
Post by Caine Lai
Post by Caine Lai
else literalOut =
literalDataGenerator.open(encOut,
Post by Caine Lai
PGPLiteralData.TEXT, fileNameIn, new Date(), new
byte[bufferSize]);
Post by Caine Lai
// Update sign and encrypt
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
input = new
FileInputStream(fileNameIn);
Post by Caine Lai
Post by Caine Lai
while((bytesRead =
input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
Post by Caine Lai
signatureGenerator.update(buffer,0,bytesRead);
Post by Caine Lai
literalOut.flush();
}
// Close Literal data stream and add
signature
Post by Caine Lai
Post by Caine Lai
literalOut.close();
literalDataGenerator.close();
if (compress)
signatureGenerator.generate().encode(compressedOut);
Post by Caine Lai
Post by Caine Lai
else
signatureGenerator.generate().encode(encOut);
Post by Caine Lai
} catch (Exception e) {
log.error(e);
throw new RuntimeException(e);
} finally {
// Close all streams
if (literalOut != null) try
{ literalOut.close(); } catch
Post by Caine Lai
(IOException e) {}
if (literalDataGenerator != null) try
{ literalDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (compressedOut != null) try
{ compressedOut.close(); }
Post by Caine Lai
catch (IOException e) {}
if (compressedDataGenerator != null)
try {
Post by Caine Lai
Post by Caine Lai
compressedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (encOut != null) try
{ encOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if (encryptedDataGenerator != null)
try {
Post by Caine Lai
Post by Caine Lai
encryptedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (finalOut != null) try
{ finalOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if (input != null) try
{ input.close(); } catch
Post by Caine Lai
Post by Caine Lai
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
private static PGPPublicKey
readPublicKeyFromCol(InputStream in)
Post by Caine Lai
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " +
pkCol.size());
Post by Caine Lai
Post by Caine Lai
Iterator it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing) it.next();
Iterator pkIt =
pkRing.getPublicKeys();
Post by Caine Lai
Post by Caine Lai
while (pkIt.hasNext()) {
PGPPublicKey key = (PGPPublicKey)
pkIt.next();
Post by Caine Lai
log.info("Encryption key = " +
key.isEncryptionKey() +
Post by Caine Lai
", Master key = " +
key.isMasterKey());
if (key.isEncryptionKey()) {
// Find out a little about the
keys in
Post by Caine Lai
the public
Post by Caine Lai
key ring.
log.info("Key Strength = " +
key.getBitStrength());
log.info("Algorithm = " +
key.getAlgorithm());
Post by Caine Lai
log.info("Bit strength = " +
key.getBitStrength());
log.info("Version = " +
key.getVersion());
Post by Caine Lai
return key;
}
}
}
return null;
}
private static PGPPrivateKey
findSecretKey(InputStream
Post by Caine Lai
keyIn, long
Post by Caine Lai
keyID, char[] pass)
throws IOException, PGPException,
NoSuchProviderException
Post by Caine Lai
{
PGPSecretKeyRingCollection pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
Post by Caine Lai
Post by Caine Lai
PGPSecretKey pgpSecKey =
pgpSec.getSecretKey(keyID);
Post by Caine Lai
Post by Caine Lai
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass,
"BC");
Post by Caine Lai
Post by Caine Lai
}
}
Any idea what could be causing this? I've found
numerous
Post by Caine Lai
reports using
Post by Caine Lai
Google, but no resolutions or follow-ups.
David Hook
2011-07-08 02:18:52 UTC
Permalink
Yep, unless you can get the signed file to fit in a byte array.

As long as you don't pass a buffer to open you will not be using packet
mode.

Regards,

David
Thanks again for the reply David. So just to be sure I understand you
correctly, does this sound like the correct sequence to do this?
-Read clear text file
-Sign it
-Write file with signature to disk and close all streams
-Read signed file
-Encrypt it
-Write encrypted file to disk and close all streams
Is this the way you are suggesting I try this? And by doing it this
way, I will not be using packet mode?
Thanks,
Caine
Yep.
By single step sign and encrypt they probably mean they want the signed
data inside the encrypted data - you'll need to do two passes as you'll
need to know the exact length of the signed data before you can encrypt
it. Of course if you're the one reading the message, rather than
creating it, this isn't a problem (as in the length is already there).
Or put another way, it'll still be one pass for them.
Regards,
David
Thanks for the reply David.
By process the data in two passes, do you mean sign the file
first and
then encrypt the file in a second pass? I've been told by
the bank
that they need single-step sign and encrypt.
I've no idea how doing it in two steps would affect the
final data
though.
Thanks,
Caine
On Thu, Jul 7, 2011 at 6:05 PM, David Hook
Packet mode is on because you're passing byte arrays
to some
of the open
encOut = encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);
There's a chance (surprisingly high
unfortunately...) that the
other end
will either not support it, or support it badly.
It'll mean you'll have to process the data in two
passes which
is a
hassle, but it's nowhere near as large a problem as
it being
unreadable.
Regards,
David
Post by Caine Lai
No, I would have no idea how to go about doing
that. Do you
mean
Post by Caine Lai
removing the PGPSignatureSubpacketGenerator? I
based the
code on the
Post by Caine Lai
SignedFileProcessor in the Bouncy Castle
examples. Is there
another
Post by Caine Lai
way to do single pass sign and encrypt?
Thanks,
Caine
On Thu, Jul 7, 2011 at 5:40 PM, David Hook
Have you tried not using packet mode?
Regards,
David
On Thu, 2011-07-07 at 17:21 -0700, Caine
Post by Caine Lai
I have been banging my head against the
wall now
for a
Post by Caine Lai
couple of weeks
Post by Caine Lai
trying to figure out why our bank cannot
decrypt a
message
Post by Caine Lai
that has
Post by Caine Lai
been single-pass signed and encrypted
using
BouncyCastle
Post by Caine Lai
PGP. The bank
Post by Caine Lai
is using McAfee E-Business Server 8.6
for
decryption.
Post by Caine Lai
Post by Caine Lai
The data is encrypted with the bank's
public key,
and is
Post by Caine Lai
signed with
Post by Caine Lai
our private key.
Using our own public key for encryption,
I am
successfully
Post by Caine Lai
able to
Post by Caine Lai
decrypt and verify the signature on a
file
generated with
Post by Caine Lai
the code
Post by Caine Lai
below. Gnupg can decrypt and verify the
file just
fine.
Post by Caine Lai
Post by Caine Lai
However, the bank is unable to decrypt
the file. I
have
Post by Caine Lai
tried first
Post by Caine Lai
turning compression off, and then
turning ASCII
armoring
Post by Caine Lai
off. Neither
Post by Caine Lai
option seems to work, and they always
get the same
error
Post by Caine Lai
message no
Post by Caine Lai
event 1: initial
event 13: BeginLex
event 8: Analyze
File is encrypted. event 9: Recipients
Secret key is required to read it.
Key for user ID "XXXXXXXXX
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file
'/somepath/FILENAME'.
Post by Caine Lai
Post by Caine Lai
Corrupt data.
Bad packet
exitcode = 32
Here is the code I am using to do the
single pass
sign and
Post by Caine Lai
Post by Caine Lai
public class PGPService {
private static final Logger log =
Logger.getLogger(PGPService.class);
static {
Security.addProvider(new
BouncyCastleProvider());
Post by Caine Lai
Post by Caine Lai
}
/**
* A simple routine that opens a key
ring file
and loads
Post by Caine Lai
the first
Post by Caine Lai
available key
* suitable for signature
generation.
Post by Caine Lai
Post by Caine Lai
*
secret key
ring
Post by Caine Lai
collection
Post by Caine Lai
from.
with using
the input
Post by Caine Lai
stream.
an issue
parsing the
Post by Caine Lai
input
Post by Caine Lai
stream.
*/
@SuppressWarnings("rawtypes")
private static PGPSecretKey
readSecretKey(InputStream
Post by Caine Lai
input)
Post by Caine Lai
throws IOException, PGPException {
PGPSecretKeyRingCollection
pgpSec = new
Post by Caine Lai
Post by Caine Lai
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
Post by Caine Lai
Post by Caine Lai
// We just loop through the
collection
till we find
Post by Caine Lai
a key
Post by Caine Lai
suitable for encryption, in the real
// world you would probably want
to be a
bit smarter
Post by Caine Lai
about
Post by Caine Lai
this.
Iterator keyRingIter =
pgpSec.getKeyRings();
Post by Caine Lai
Post by Caine Lai
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter =
keyRing.getSecretKeys();
Post by Caine Lai
Post by Caine Lai
while (keyIter.hasNext()) {
PGPSecretKey key =
(PGPSecretKey)keyIter.next();
Post by Caine Lai
if (key.isSigningKey())
{
Post by Caine Lai
Post by Caine Lai
return key;
}
}
}
throw new
IllegalArgumentException("Can't
find
Post by Caine Lai
signing key in
Post by Caine Lai
key ring.");
}
/**
* Single pass signs and encrypts
the given
file to the
Post by Caine Lai
given
Post by Caine Lai
output file using the provided keys.
*
location
of the
Post by Caine Lai
source input
Post by Caine Lai
file.
location
of the
Post by Caine Lai
destination
Post by Caine Lai
output file.
stream for
the
Post by Caine Lai
private key
Post by Caine Lai
file.
password
for the
Post by Caine Lai
private key
Post by Caine Lai
file.
public
encryption
Post by Caine Lai
key.
not to
ASCII armor
Post by Caine Lai
the
Post by Caine Lai
output.
*/
@SuppressWarnings("rawtypes")
public static void
signAndEncrypt(String
fileNameIn,
Post by Caine Lai
String
Post by Caine Lai
fileNameOut, InputStream privateKeyIn,
String
Post by Caine Lai
privateKeyPassword,
Post by Caine Lai
PGPPublicKey publicEncryptionKey,
boolean
armoredOutput,
Post by Caine Lai
boolean
Post by Caine Lai
compress) {
int bufferSize = 1<<16;
InputStream input = null;
OutputStream finalOut = null;
OutputStream encOut = null;
OutputStream compressedOut =
null;
Post by Caine Lai
Post by Caine Lai
OutputStream literalOut = null;
PGPEncryptedDataGenerator
encryptedDataGenerator =
Post by Caine Lai
null;
Post by Caine Lai
PGPCompressedDataGenerator
compressedDataGenerator =
Post by Caine Lai
null;
Post by Caine Lai
PGPSignatureGenerator
signatureGenerator =
null;
Post by Caine Lai
Post by Caine Lai
PGPLiteralDataGenerator
literalDataGenerator = null;
Post by Caine Lai
Post by Caine Lai
try {
File output = new
File(fileNameOut);
Post by Caine Lai
Post by Caine Lai
OutputStream out = new
FileOutputStream(output);
Post by Caine Lai
Post by Caine Lai
if (armoredOutput) out = new
ArmoredOutputStream(out);
Post by Caine Lai
// ? Use BCPGOutputStreams ?
// Init encrypted data
generator
Post by Caine Lai
Post by Caine Lai
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5,
Post by Caine Lai
true, new
Post by Caine Lai
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
Post by Caine Lai
Post by Caine Lai
finalOut = new
BufferedOutputStream(out,
Post by Caine Lai
bufferSize);
Post by Caine Lai
encOut =
encryptedDataGenerator.open(finalOut,
Post by Caine Lai
new
Post by Caine Lai
byte[bufferSize]);
// Init compression
if (compress) {
compressedDataGenerator
= new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
Post by Caine Lai
Post by Caine Lai
compressedOut = new
BufferedOutputStream(compressedDataGenerator.open(encOut));
Post by Caine Lai
Post by Caine Lai
}
// Init signature
PGPSecretKey pgpSec =
readSecretKey(privateKeyIn);
Post by Caine Lai
PGPPrivateKey pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(),
Post by Caine Lai
Post by Caine Lai
"BC");
signatureGenerator = new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
Post by Caine Lai
Post by Caine Lai
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
Post by Caine Lai
Post by Caine Lai
pgpPrivKey);
Iterator it =
pgpSec.getPublicKey().getUserIDs();
Post by Caine Lai
if (it.hasNext()) {
PGPSignatureSubpacketGenerator
spGen = new
Post by Caine Lai
Post by Caine Lai
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false,
Post by Caine Lai
(String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
Post by Caine Lai
Post by Caine Lai
}
PGPOnePassSignature
onePassSignature =
signatureGenerator.generateOnePassVersion(false);
Post by Caine Lai
Post by Caine Lai
if (compress)
onePassSignature.encode(compressedOut);
Post by Caine Lai
else
onePassSignature.encode(encOut);
Post by Caine Lai
Post by Caine Lai
// Create the Literal Data
generator
Output
Post by Caine Lai
stream which
Post by Caine Lai
writes to the compression stream
literalDataGenerator = new
PGPLiteralDataGenerator(true);
Post by Caine Lai
if (compress) literalOut =
literalDataGenerator.open(compressedOut,
PGPLiteralData.BINARY,
Post by Caine Lai
output.getName(), new Date(), new
byte[bufferSize]);
Post by Caine Lai
Post by Caine Lai
else literalOut =
literalDataGenerator.open(encOut,
Post by Caine Lai
PGPLiteralData.TEXT, fileNameIn, new
Date(), new
Post by Caine Lai
byte[bufferSize]);
Post by Caine Lai
// Update sign and encrypt
byte[] buffer = new
byte[bufferSize];
Post by Caine Lai
Post by Caine Lai
int bytesRead = 0;
input = new
FileInputStream(fileNameIn);
Post by Caine Lai
Post by Caine Lai
while((bytesRead =
input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
Post by Caine Lai
Post by Caine Lai
literalOut.flush();
}
// Close Literal data stream
and add
signature
Post by Caine Lai
Post by Caine Lai
literalOut.close();
literalDataGenerator.close();
Post by Caine Lai
Post by Caine Lai
if (compress)
signatureGenerator.generate().encode(compressedOut);
Post by Caine Lai
Post by Caine Lai
else
signatureGenerator.generate().encode(encOut);
Post by Caine Lai
Post by Caine Lai
} catch (Exception e) {
log.error(e);
throw new
RuntimeException(e);
Post by Caine Lai
Post by Caine Lai
} finally {
// Close all streams
if (literalOut != null) try
{ literalOut.close(); } catch
Post by Caine Lai
(IOException e) {}
if (literalDataGenerator !=
null) try
Post by Caine Lai
Post by Caine Lai
{ literalDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (compressedOut != null)
try
Post by Caine Lai
{ compressedOut.close(); }
Post by Caine Lai
catch (IOException e) {}
if
(compressedDataGenerator != null)
try {
Post by Caine Lai
Post by Caine Lai
compressedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (encOut != null) try
{ encOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if (encryptedDataGenerator !
= null)
try {
Post by Caine Lai
Post by Caine Lai
encryptedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (finalOut != null) try
{ finalOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if (input != null) try
{ input.close(); } catch
Post by Caine Lai
Post by Caine Lai
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
private static PGPPublicKey
readPublicKeyFromCol(InputStream in)
Post by Caine Lai
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol
= new
Post by Caine Lai
Post by Caine Lai
PGPPublicKeyRingCollection(in);
log.info("Key ring size = " +
pkCol.size());
Post by Caine Lai
Post by Caine Lai
Iterator it =
pkCol.getKeyRings();
Post by Caine Lai
Post by Caine Lai
while (it.hasNext()) {
pkRing = (PGPPublicKeyRing)
it.next();
Post by Caine Lai
Post by Caine Lai
Iterator pkIt =
pkRing.getPublicKeys();
Post by Caine Lai
Post by Caine Lai
while (pkIt.hasNext()) {
PGPPublicKey key =
(PGPPublicKey)
Post by Caine Lai
pkIt.next();
Post by Caine Lai
log.info("Encryption key
= " +
Post by Caine Lai
key.isEncryptionKey() +
Post by Caine Lai
", Master key = " +
key.isMasterKey());
if
(key.isEncryptionKey()) {
Post by Caine Lai
Post by Caine Lai
// Find out a little
about the
keys in
Post by Caine Lai
the public
Post by Caine Lai
key ring.
log.info("Key
Strength = " +
Post by Caine Lai
Post by Caine Lai
key.getBitStrength());
log.info("Algorithm
= " +
Post by Caine Lai
key.getAlgorithm());
Post by Caine Lai
log.info("Bit
strength = " +
Post by Caine Lai
Post by Caine Lai
key.getBitStrength());
log.info("Version =
" +
Post by Caine Lai
key.getVersion());
Post by Caine Lai
return key;
}
}
}
return null;
}
private static PGPPrivateKey
findSecretKey(InputStream
Post by Caine Lai
keyIn, long
Post by Caine Lai
keyID, char[] pass)
throws IOException,
PGPException,
Post by Caine Lai
NoSuchProviderException
Post by Caine Lai
{
PGPSecretKeyRingCollection
pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
Post by Caine Lai
Post by Caine Lai
PGPSecretKey pgpSecKey =
pgpSec.getSecretKey(keyID);
Post by Caine Lai
Post by Caine Lai
if (pgpSecKey == null) {
return null;
}
return
pgpSecKey.extractPrivateKey(pass,
"BC");
Post by Caine Lai
Post by Caine Lai
}
}
Any idea what could be causing this?
I've found
numerous
Post by Caine Lai
reports using
Post by Caine Lai
Google, but no resolutions or
follow-ups.
David Hook
2011-07-10 00:01:29 UTC
Permalink
It just gets stranger and stranger! Thanks for the follow up, I'm sure
it will save others similar pain and suffering.

Regards,

David
Great, thanks again for all your help David.
Just to follow up, I did hear back from the bank this morning finally,
and they were able to successfully decrypt and verify a file I sent
over with my original code. The file had to have BOTH compression and
ASCII armoring turned off for it to work. I did try this option
earlier with them but it turned out there was a bug in the commons net
ftp 3.0 code that was causing the binary file to only partially
transfer. Made finding the right combination of switches difficult
when there was more than one culprit for the problem.
I guess if we wanted to use ASCII armoring I should try your
suggestion to see if it solves the compatibility issue.
Thanks again,
Caine
Yep, unless you can get the signed file to fit in a byte array.
As long as you don't pass a buffer to open you will not be using packet
mode.
Regards,
David
Thanks again for the reply David. So just to be sure I
understand you
correctly, does this sound like the correct sequence to do
this?
-Read clear text file
-Sign it
-Write file with signature to disk and close all streams
-Read signed file
-Encrypt it
-Write encrypted file to disk and close all streams
Is this the way you are suggesting I try this? And by doing
it this
way, I will not be using packet mode?
Thanks,
Caine
On Thu, Jul 7, 2011 at 6:29 PM, David Hook
Yep.
By single step sign and encrypt they probably mean
they want
the signed
data inside the encrypted data - you'll need to do
two passes
as you'll
need to know the exact length of the signed data
before you
can encrypt
it. Of course if you're the one reading the message,
rather
than
creating it, this isn't a problem (as in the length
is already
there).
Or put another way, it'll still be one pass for
them.
Regards,
David
Thanks for the reply David.
By process the data in two passes, do you mean
sign the file
first and
then encrypt the file in a second pass? I've been
told by
the bank
that they need single-step sign and encrypt.
I've no idea how doing it in two steps would
affect the
final data
though.
Thanks,
Caine
On Thu, Jul 7, 2011 at 6:05 PM, David Hook
Packet mode is on because you're passing
byte arrays
to some
of the open
encOut =
encryptedDataGenerator.open(finalOut, new
byte[bufferSize]);
There's a chance (surprisingly high
unfortunately...) that the
other end
will either not support it, or support it
badly.
It'll mean you'll have to process the data
in two
passes which
is a
hassle, but it's nowhere near as large a
problem as
it being
unreadable.
Regards,
David
On Thu, 2011-07-07 at 17:51 -0700, Caine
Post by Caine Lai
No, I would have no idea how to go about
doing
that. Do you
mean
Post by Caine Lai
removing the
PGPSignatureSubpacketGenerator? I
based the
code on the
Post by Caine Lai
SignedFileProcessor in the Bouncy Castle
examples. Is there
another
Post by Caine Lai
way to do single pass sign and encrypt?
Thanks,
Caine
On Thu, Jul 7, 2011 at 5:40 PM, David
Hook
Post by Caine Lai
Have you tried not using packet
mode?
Post by Caine Lai
Regards,
David
On Thu, 2011-07-07 at 17:21
-0700, Caine
Post by Caine Lai
Post by Caine Lai
I have been banging my head
against the
wall now
for a
Post by Caine Lai
couple of weeks
Post by Caine Lai
trying to figure out why our
bank cannot
decrypt a
message
Post by Caine Lai
that has
Post by Caine Lai
been single-pass signed and
encrypted
using
BouncyCastle
Post by Caine Lai
PGP. The bank
Post by Caine Lai
is using McAfee E-Business
Server 8.6
for
decryption.
Post by Caine Lai
Post by Caine Lai
The data is encrypted with the
bank's
public key,
and is
Post by Caine Lai
signed with
Post by Caine Lai
our private key.
Using our own public key for
encryption,
I am
successfully
Post by Caine Lai
able to
Post by Caine Lai
decrypt and verify the
signature on a
file
generated with
Post by Caine Lai
the code
Post by Caine Lai
below. Gnupg can decrypt and
verify the
file just
fine.
Post by Caine Lai
Post by Caine Lai
However, the bank is unable to
decrypt
the file. I
have
Post by Caine Lai
tried first
Post by Caine Lai
turning compression off, and
then
turning ASCII
armoring
Post by Caine Lai
off. Neither
Post by Caine Lai
option seems to work, and they
always
get the same
error
Post by Caine Lai
message no
Post by Caine Lai
event 1: initial
event 13: BeginLex
event 8: Analyze
Recipients
Post by Caine Lai
Post by Caine Lai
Secret key is required to read
it.
Post by Caine Lai
Post by Caine Lai
Key for user ID "XXXXXXXXX
event 6: Passphrase
event 23: Decryption
symmetric cipher used: CAST5
event 3: error -11391
event 2: final
Error decrypting file
'/somepath/FILENAME'.
Post by Caine Lai
Post by Caine Lai
Corrupt data.
Bad packet
exitcode = 32
Here is the code I am using to
do the
single pass
sign and
Post by Caine Lai
Post by Caine Lai
public class PGPService {
private static final
Logger log =
Logger.getLogger(PGPService.class);
Post by Caine Lai
Post by Caine Lai
static {
Security.addProvider(new
BouncyCastleProvider());
Post by Caine Lai
Post by Caine Lai
}
/**
* A simple routine that
opens a key
ring file
and loads
Post by Caine Lai
the first
Post by Caine Lai
available key
* suitable for signature
generation.
Post by Caine Lai
Post by Caine Lai
*
read the
secret key
ring
Post by Caine Lai
collection
Post by Caine Lai
from.
a problem
with using
the input
Post by Caine Lai
stream.
there is
an issue
parsing the
Post by Caine Lai
input
Post by Caine Lai
stream.
*/
@SuppressWarnings("rawtypes")
Post by Caine Lai
Post by Caine Lai
private static
PGPSecretKey
readSecretKey(InputStream
Post by Caine Lai
input)
Post by Caine Lai
throws IOException,
PGPException {
PGPSecretKeyRingCollection
pgpSec = new
Post by Caine Lai
Post by Caine Lai
PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
Post by Caine Lai
Post by Caine Lai
// We just loop
through the
collection
till we find
Post by Caine Lai
a key
Post by Caine Lai
suitable for encryption, in
the real
Post by Caine Lai
Post by Caine Lai
// world you would
probably want
to be a
bit smarter
Post by Caine Lai
about
Post by Caine Lai
this.
Iterator keyRingIter =
pgpSec.getKeyRings();
Post by Caine Lai
Post by Caine Lai
while
(keyRingIter.hasNext()) {
Post by Caine Lai
Post by Caine Lai
PGPSecretKeyRing
keyRing =
(PGPSecretKeyRing)keyRingIter.next();
Post by Caine Lai
Post by Caine Lai
Iterator keyIter =
keyRing.getSecretKeys();
Post by Caine Lai
Post by Caine Lai
while
(keyIter.hasNext()) {
Post by Caine Lai
Post by Caine Lai
PGPSecretKey
key =
Post by Caine Lai
(PGPSecretKey)keyIter.next();
Post by Caine Lai
if
(key.isSigningKey())
{
Post by Caine Lai
Post by Caine Lai
return
key;
Post by Caine Lai
Post by Caine Lai
}
}
}
throw new
IllegalArgumentException("Can't
find
Post by Caine Lai
signing key in
Post by Caine Lai
key ring.");
}
/**
* Single pass signs and
encrypts
the given
file to the
Post by Caine Lai
given
Post by Caine Lai
output file using the provided
keys.
Post by Caine Lai
Post by Caine Lai
*
name and
location
of the
Post by Caine Lai
source input
Post by Caine Lai
file.
The name and
location
of the
Post by Caine Lai
destination
Post by Caine Lai
output file.
The input
stream for
the
Post by Caine Lai
private key
Post by Caine Lai
file.
privateKeyPassword - The
password
for the
Post by Caine Lai
private key
Post by Caine Lai
file.
publicEncryptionKey - The
public
encryption
Post by Caine Lai
key.
Whether or
not to
ASCII armor
Post by Caine Lai
the
Post by Caine Lai
output.
*/
@SuppressWarnings("rawtypes")
Post by Caine Lai
Post by Caine Lai
public static void
signAndEncrypt(String
fileNameIn,
Post by Caine Lai
String
Post by Caine Lai
fileNameOut, InputStream
privateKeyIn,
String
Post by Caine Lai
privateKeyPassword,
Post by Caine Lai
PGPPublicKey
publicEncryptionKey,
boolean
armoredOutput,
Post by Caine Lai
boolean
Post by Caine Lai
compress) {
int bufferSize =
1<<16;
Post by Caine Lai
Post by Caine Lai
InputStream input =
null;
Post by Caine Lai
Post by Caine Lai
OutputStream finalOut
= null;
Post by Caine Lai
Post by Caine Lai
OutputStream encOut =
null;
Post by Caine Lai
Post by Caine Lai
OutputStream
compressedOut =
null;
Post by Caine Lai
Post by Caine Lai
OutputStream
literalOut = null;
PGPEncryptedDataGenerator
encryptedDataGenerator =
Post by Caine Lai
null;
PGPCompressedDataGenerator
compressedDataGenerator =
Post by Caine Lai
null;
Post by Caine Lai
PGPSignatureGenerator
signatureGenerator =
null;
PGPLiteralDataGenerator
literalDataGenerator = null;
Post by Caine Lai
Post by Caine Lai
try {
File output = new
File(fileNameOut);
Post by Caine Lai
Post by Caine Lai
OutputStream out =
new
FileOutputStream(output);
Post by Caine Lai
Post by Caine Lai
if (armoredOutput)
out = new
Post by Caine Lai
ArmoredOutputStream(out);
Post by Caine Lai
// ? Use
BCPGOutputStreams ?
Post by Caine Lai
Post by Caine Lai
// Init encrypted
data
generator
encryptedDataGenerator = new
PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5,
Post by Caine Lai
true, new
Post by Caine Lai
SecureRandom(), "BC");
encryptedDataGenerator.addMethod(publicEncryptionKey);
Post by Caine Lai
Post by Caine Lai
finalOut = new
BufferedOutputStream(out,
Post by Caine Lai
bufferSize);
Post by Caine Lai
encOut =
encryptedDataGenerator.open(finalOut,
Post by Caine Lai
new
Post by Caine Lai
byte[bufferSize]);
// Init
compression
Post by Caine Lai
Post by Caine Lai
if (compress) {
compressedDataGenerator
= new
PGPCompressedDataGenerator(PGPCompressedData.ZLIB);
Post by Caine Lai
Post by Caine Lai
compressedOut
= new
BufferedOutputStream(compressedDataGenerator.open(encOut));
Post by Caine Lai
Post by Caine Lai
}
// Init signature
PGPSecretKey
pgpSec =
Post by Caine Lai
readSecretKey(privateKeyIn);
Post by Caine Lai
PGPPrivateKey
pgpPrivKey =
pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(),
Post by Caine Lai
Post by Caine Lai
"BC");
signatureGenerator
= new
PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(),
Post by Caine Lai
Post by Caine Lai
PGPUtil.SHA1, "BC");
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT,
Post by Caine Lai
Post by Caine Lai
pgpPrivKey);
Iterator it =
pgpSec.getPublicKey().getUserIDs();
Post by Caine Lai
Post by Caine Lai
if (it.hasNext())
{
PGPSignatureSubpacketGenerator
spGen = new
PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false,
Post by Caine Lai
(String)it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
Post by Caine Lai
Post by Caine Lai
}
PGPOnePassSignature
onePassSignature =
signatureGenerator.generateOnePassVersion(false);
Post by Caine Lai
Post by Caine Lai
if (compress)
onePassSignature.encode(compressedOut);
Post by Caine Lai
Post by Caine Lai
else
onePassSignature.encode(encOut);
Post by Caine Lai
Post by Caine Lai
// Create the
Literal Data
generator
Output
Post by Caine Lai
stream which
Post by Caine Lai
writes to the compression
stream
literalDataGenerator = new
Post by Caine Lai
PGPLiteralDataGenerator(true);
Post by Caine Lai
if (compress)
literalOut =
literalDataGenerator.open(compressedOut,
Post by Caine Lai
PGPLiteralData.BINARY,
Post by Caine Lai
output.getName(), new Date(),
new
byte[bufferSize]);
Post by Caine Lai
Post by Caine Lai
else literalOut =
literalDataGenerator.open(encOut,
Post by Caine Lai
Post by Caine Lai
PGPLiteralData.TEXT,
fileNameIn, new
Date(), new
Post by Caine Lai
byte[bufferSize]);
Post by Caine Lai
// Update sign and
encrypt
Post by Caine Lai
Post by Caine Lai
byte[] buffer =
new
byte[bufferSize];
Post by Caine Lai
Post by Caine Lai
int bytesRead = 0;
input = new
FileInputStream(fileNameIn);
Post by Caine Lai
Post by Caine Lai
while((bytesRead =
input.read(buffer)) != -1) {
literalOut.write(buffer,0,bytesRead);
signatureGenerator.update(buffer,0,bytesRead);
literalOut.flush();
Post by Caine Lai
Post by Caine Lai
}
// Close Literal
data stream
and add
signature
literalOut.close();
literalDataGenerator.close();
Post by Caine Lai
Post by Caine Lai
if (compress)
signatureGenerator.generate().encode(compressedOut);
Post by Caine Lai
Post by Caine Lai
else
signatureGenerator.generate().encode(encOut);
Post by Caine Lai
Post by Caine Lai
} catch (Exception e)
{
Post by Caine Lai
Post by Caine Lai
log.error(e);
throw new
RuntimeException(e);
Post by Caine Lai
Post by Caine Lai
} finally {
// Close all
streams
Post by Caine Lai
Post by Caine Lai
if (literalOut !=
null) try
Post by Caine Lai
{ literalOut.close(); } catch
Post by Caine Lai
(IOException e) {}
if
(literalDataGenerator !=
null) try
{ literalDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if
(compressedOut != null)
try
Post by Caine Lai
{ compressedOut.close(); }
Post by Caine Lai
catch (IOException e) {}
if
(compressedDataGenerator != null)
try {
compressedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (encOut !=
null) try
{ encOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if
(encryptedDataGenerator !
= null)
try {
encryptedDataGenerator.close(); } catch
(IOException e) {}
Post by Caine Lai
Post by Caine Lai
if (finalOut !=
null) try
{ finalOut.close(); }
Post by Caine Lai
catch
Post by Caine Lai
(IOException e) {}
if (input != null)
try
{ input.close(); } catch
Post by Caine Lai
Post by Caine Lai
(IOException e) {}
}
}
@SuppressWarnings("rawtypes")
Post by Caine Lai
Post by Caine Lai
private static
PGPPublicKey
Post by Caine Lai
readPublicKeyFromCol(InputStream
in)
Post by Caine Lai
Post by Caine Lai
throws Exception {
PGPPublicKeyRing
pkRing = null;
PGPPublicKeyRingCollection pkCol
= new
PGPPublicKeyRingCollection(in);
Post by Caine Lai
Post by Caine Lai
log.info("Key ring
size = " +
pkCol.size());
Post by Caine Lai
Post by Caine Lai
Iterator it =
pkCol.getKeyRings();
Post by Caine Lai
Post by Caine Lai
while (it.hasNext()) {
pkRing =
(PGPPublicKeyRing)
it.next();
Post by Caine Lai
Post by Caine Lai
Iterator pkIt =
pkRing.getPublicKeys();
Post by Caine Lai
Post by Caine Lai
while
(pkIt.hasNext()) {
Post by Caine Lai
Post by Caine Lai
PGPPublicKey
key =
(PGPPublicKey)
Post by Caine Lai
pkIt.next();
log.info("Encryption key
= " +
Post by Caine Lai
key.isEncryptionKey() +
Post by Caine Lai
", Master key = " +
key.isMasterKey());
Post by Caine Lai
Post by Caine Lai
if
(key.isEncryptionKey()) {
Post by Caine Lai
Post by Caine Lai
// Find
out a little
about the
keys in
Post by Caine Lai
the public
Post by Caine Lai
key ring.
log.info("Key
Strength = " +
Post by Caine Lai
Post by Caine Lai
key.getBitStrength());
log.info("Algorithm
= " +
Post by Caine Lai
key.getAlgorithm());
log.info("Bit
strength = " +
Post by Caine Lai
Post by Caine Lai
key.getBitStrength());
log.info("Version =
" +
Post by Caine Lai
key.getVersion());
Post by Caine Lai
return
key;
Post by Caine Lai
Post by Caine Lai
}
}
}
return null;
}
private static
PGPPrivateKey
findSecretKey(InputStream
Post by Caine Lai
keyIn, long
Post by Caine Lai
keyID, char[] pass)
throws
IOException,
PGPException,
Post by Caine Lai
NoSuchProviderException
Post by Caine Lai
{
PGPSecretKeyRingCollection
pgpSec = new
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
Post by Caine Lai
Post by Caine Lai
PGPSecretKey pgpSecKey
=
pgpSec.getSecretKey(keyID);
Post by Caine Lai
Post by Caine Lai
if (pgpSecKey == null)
{
Post by Caine Lai
Post by Caine Lai
return null;
}
return
pgpSecKey.extractPrivateKey(pass,
"BC");
Post by Caine Lai
Post by Caine Lai
}
}
Any idea what could be causing
this?
I've found
numerous
Post by Caine Lai
reports using
Post by Caine Lai
Google, but no resolutions or
follow-ups.
Loading...