I am trying to implement PGP encryption in Java using Bouncy Castle, also using some of the examples provided by them.
But if I try and decrypt the message I just encrypted, it does not work. The keys and the decryption method seem to be ok, because I can encrypt using an external tool (link) and then successfully decrypt it here.
public static void main(String[] args) throws PGPException, IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
Security.addProvider(new BouncyCastleProvider());
byte[] msg = ("Test blabla BLA").getBytes();
byte[] encData = encrypt(msg, publicKey);
System.out.println(new String(encData));
System.err.println("DECRYPTED");
System.out.println(decrypt(IOUtils.toInputStream(new String(encData), StandardCharsets.UTF_8), privateKey, passphrase));
System.err.println("DECRYPTED external");
String testEncryptedMsg = "-----BEGIN PGP MESSAGE-----\n" +
"Version: BCPG C# v1.6.1.0\n" +
"\n" +
"hQIMA4p9BgtBOg+BARAAiLdmGZBupsSkrji1qdC/y6KACuaWytcjVg3LWudWRlH8\n" +
"Ye1U0bz+HYc6mLt21RivAZ3p+lPXPzh/h0GVLW/aI2ngJracL+iEA7eam5/H3NQV\n" +
"2o0CR1mjw4xOf0XwDxaLrnivdeuWniXiZyFN7Ud7lmNG+EmQ0d5ZfR7KEnTJNjSe\n" +
"FpzwRffBG5lKB4CxF49jBp+Iupdv4A5JzHuDVBkypPMNhS/UEbuPOt5cfmddYVvW\n" +
"gtDM3rX+ePBhg7d/mVkiDT2KM0Cr7GSrdZ8q83fF4sat3Xp8OHMq61GWriNK4gwb\n" +
"ViT/vmEsY0n55TVgN5VagMZJJlEThkqWE2wpEjq4HM8pNxR4PvP5inqP5oipn8Os\n" +
"Nq2a5f77BS7GB9NQ+hnaLSBsywJkZVKqygN81MeHBnNrVXFQ/Hqg24BLwk49bOuH\n" +
"jTUzorudCnjj/p8/WiyR+PuESkQDLKpo1z9KGEE/rKjTqAwH/fBKJ73XpmAWwd4U\n" +
"1hv/EdF+XDZv7XwxeVjSIK2inAjdNz+way1WNY3qouo7G+gjKf1gbL14q2HVPnd/\n" +
"7mfiW3uWCQ7GhXlHtd1E0WeK2296TdBuSGAvLlVxI4xepsiuVw+zC4BxvAkTXB/a\n" +
"HyJZhKPksHMRCt8ZxitMfhdvMNGjc4MDhv1MLqKijpagKhgrmDTiJRMb3ng6QLvJ\n" +
"L2GICyuS4aIsz6XiCQvZG8ebfb0J4uogbb5HxS2fGFT+Y/VgpCnwhwj6LnLBy1Q3\n" +
"=D/1d\n" +
"-----END PGP MESSAGE-----\n";
System.out.println(decrypt(IOUtils.toInputStream(testEncryptedMsg, StandardCharsets.UTF_8), privateKey, passphrase));
}
I think the problem is on the encryption side, but I cannot figure out what exactly it is. Does anyone have any ideas?
public static byte[] encrypt(byte[] bytes, String publicKey) throws IOException {
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
try {
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_128)
.setSecureRandom(new SecureRandom())
.setWithIntegrityPacket(true)
.setProvider("BC"));
PGPPublicKey encryptionKey = readPublicKey(publicKey);
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey).setProvider("BC"));
ArmoredOutputStream aOut = new ArmoredOutputStream(encOut);
OutputStream cOut = encGen.open(aOut, bytes.length);
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(aOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
pOut.write(bytes);
pOut.close();
// finish the encryption
cOut.close();
aOut.close();
} catch (PGPException e) {
log.error("Exception encountered while encoding data.", e);
}
return encOut.toByteArray();
}
public static String decrypt(InputStream in, String secretKey, String passphrase) throws IOException {
String content = null;
try {
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
// the first object might be a PGP marker packet.
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
// find the secret key
Iterator<PGPEncryptedData> it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(new ByteArrayInputStream(secretKey.getBytes())), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = findSecretKey(pgpSec, pbe.getKeyID(), passphrase.toCharArray());
}
if (sKey == null) {
log.error("Secret key for message not found.");
throw new IllegalArgumentException("secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
Object message = plainFact.nextObject();
if (message instanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) message;
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
message = pgpFact.nextObject();
}
if (message instanceof PGPLiteralData) {
PGPLiteralData ld = (PGPLiteralData) message;
content = new String(ld.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
} else if (message instanceof PGPOnePassSignatureList) {
throw new PGPException("encrypted message contains a signed message - not literal data.");
} else {
throw new PGPException("message is not a simple encrypted file - type unknown.");
}
if (pbe.isIntegrityProtected()) {
if (!pbe.verify()) {
log.error("message failed integrity check");
} else {
log.info("message integrity check passed");
}
} else {
log.warn("no message integrity check");
}
} catch (PGPException e) {
log.error("Exception encountered while decrypting file.", e);
}
return content;
}
private static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws PGPException {
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
}
private static PGPPublicKey readPublicKey(String publicKey) throws IOException, PGPException {
InputStream input = IOUtils.toInputStream(publicKey, StandardCharsets.UTF_8);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
Iterator<PGPPublicKeyRing> keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = keyRingIter.next();
Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = keyIter.next();
if (key.isEncryptionKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
Here is the encryption method that eventually worked for me.
It helped debugging together with the examples provided by the BCFipsIn100 book.
public byte[] encrypt(byte[] bytes, String publicKey) throws IOException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] compressedData = compress(bytes);
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(PROVIDER));
PGPPublicKey encryptionKey = readPublicKey(publicKey);
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey).setProvider(PROVIDER));
ArmoredOutputStream aOut = new ArmoredOutputStream(byteArrayOutputStream);
OutputStream cOut = encGen.open(aOut, compressedData.length);
cOut.write(compressedData);
cOut.close();
aOut.close();
return byteArrayOutputStream.toByteArray();
} catch (PGPException e) {
log.error("Exception encountered while encoding data.", e);
}
return new byte[0];
}
private static byte[] compress(byte[] clearData) throws IOException {
try (ByteArrayOutputStream bOut = new ByteArrayOutputStream()) {
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);
OutputStream cos = comData.open(bOut);
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos,
PGPLiteralData.BINARY,
PGPLiteralData.CONSOLE,
clearData.length,
new Date());
pOut.write(clearData);
pOut.close();
comData.close();
return bOut.toByteArray();
}
}
There are some errors in your encrypt() method code:
First and foremost, in this line your are opening the literal data stream directly on your armored output stream, while you should open it on your encryption stream:
OutputStream pOut = lData.open(aOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
// replace with
OutputStream pOut = lData.open(cOut, PGPLiteralData.UTF8, PGPLiteralData.CONSOLE, bytes.length, new Date());
Furthermore you should replace the line
OutputStream cOut = encGen.open(aOut, bytes.length);
// with
OutputStream cOut = encGen.open(aOut, new byte[1<<9]);
Otherwise you will run into encoding issues.
These changes should make your code run.
I however recommend using a library such as PGPainless (disclaimer: author here) which does all the low level stream wrapping and checking for you. On top of that it does proper signature verification, which most other Bouncycastle based libraries lack.
While going with sign encrypt then decrypt and verify, I keep getting unknown object in stream while verifying. Message integrity check passed but when I try to verify in the very next line after decrypt I'm getting the above said error.
private static void encryptFile(
String outFileName,
OutputStream out,
String fileName,
PGPPublicKey encKey,
String sKeyFileName,
char[] passPhrase,
boolean armor,
boolean withIntegrityCheck)
throws Exception
{
if (armor)
{
out = new ArmoredOutputStream(out);
}
try
{
byte[] bytes = PGPKeyUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(), "BC");
encGen.addMethod(encKey);
OutputStream cOut = encGen.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
out.close();
cOut.close();
if (armor)
{
out.close();
}
encGen.close();
}
catch (PGPException e)
{
System.err.println(e);
if (e.getUnderlyingException() != null)
{
e.getUnderlyingException().printStackTrace();
}
}
}
public static void signFile(
String fileName,
InputStream keyIn,
OutputStream out,
char[] pass,
boolean armor)
throws IOException, NoSuchAlgorithmException, NoSuchProviderException, PGPException, SignatureException
{
if (armor)
{
out = new ArmoredOutputStream(out);
}
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(out));
sGen.generateOnePassVersion(false).encode(bOut);
File file = new File(fileName);
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
OutputStream lOut = lGen.open(bOut, PGPLiteralData.BINARY, file);
FileInputStream fIn = new FileInputStream(file);
int ch = 0;
while ((ch = fIn.read()) >= 0)
{
lOut.write(ch);
sGen.update((byte)ch);
}
lGen.close();
sGen.generate().encode(bOut);
cGen.close();
bOut.close();
fIn.close();
lOut.close();
if (armor)
{
out.close();
}
System.out.println("Successfully signed");
}
First I sign using signFile and then I encrypt the file using encrypt method.
I've tested your code
Encrypt & signed some of my text file then decrypt it back.
then I've also got a error message when decryption.
The message was -
unknown object in stream: 56
java.io.IOException: unknown object in stream: 56
at org.bouncycastle.openpgp.PGPObjectFactory.nextObject(Unknown Source)
at FileEncryptTest._decrypt(FileEncryptTest.java:205)
at FileEncryptTest.decryptFile(FileEncryptTest.java:170)
at FileEncryptTest.main(FileEncryptTest.java:157)
I am not sure the same message with yours, but the signFile method must be looks like as follows,
private static void signFile(String fileName, InputStream keyIn, OutputStream out, char[] pass, boolean armor)
throws GeneralSecurityException, IOException, PGPException {
if (armor) {
out = new ArmoredOutputStream(out);
}
PGPSecretKey pgpSec = readSecretKey(keyIn);
PGPPrivateKey pgpPrivKey = pgpSec
.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
PGPSignatureGenerator sGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC"));
sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
BCPGOutputStream bOut = new BCPGOutputStream(out);
InputStream fIn = new BufferedInputStream(new FileInputStream(fileName));
byte[] buf = new byte[1024];
int len;
while ((len = fIn.read(buf)) > 0) {
sGen.update(buf, 0, len);
}
//int ch;
//while ((ch = fIn.read()) >= 0) {
// sGen.update((byte) ch);
//}
fIn.close();
sGen.generate().encode(bOut);
if (armor) {
out.close();
}
out.close();
bOut.close();
}
My bouncycastle library is exactly bcpg-jdk15on-158.jar - the latest one.
So, API might be different some part of code.
I added it all in my main method.
First, my private & public key file declaration.
private static File publicKeyFile = new File("resource/PGP1D0.pkr");
private static File privateKeyFile = new File("resource/PGP1D0.skr");
private static String privateKeyPassword = "passphrase";
Sign & encrypt a file when the isEncrypt is true, otherwise decrypt the file.
The original file is tile_doc.in and tile_doc.signed.in after signing with encryption when the isEncrypt flag is true, Then let the flag to false and run.
You can see the tile_doc.out file in the resource folder.
private static final boolean isEncrypt = false;
public static void main(String[] args) {
Security.addProvider(new BouncyCastleProvider());
String outFileName = "resource/tile_doc.signed.in";
String recoverFile = "resource/tile_doc.out";
OutputStream out = null;
InputStream keyIn = null;
InputStream outFileIn = null;
String fileName = "resource/tile_doc.in";
PGPPublicKey encKey = null;
char[] passPhrase = privateKeyPassword.toCharArray();
boolean armor = false;
boolean withIntegrityCheck = true;
if (isEncrypt) {
try {
keyIn = new BufferedInputStream(new FileInputStream(privateKeyFile));
out = new BufferedOutputStream(new FileOutputStream(outFileName));
encKey = readPublicKeyFromCol(new FileInputStream(publicKeyFile));
//
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
signFile(fileName, keyIn, out, passPhrase, armor);
out = new BufferedOutputStream(new FileOutputStream(outFileName));
} catch (GeneralSecurityException | IOException | PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
encryptFile(outFileName, out, fileName, encKey, passPhrase, armor, withIntegrityCheck);
} else {
try {
keyIn = new BufferedInputStream(new FileInputStream(privateKeyFile));
outFileIn = new BufferedInputStream(new FileInputStream(outFileName));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decryptFile(outFileIn, keyIn, passPhrase, recoverFile);
}
}
Then, my decryptFile method have two parts,
one is a base64 encoding with binary contents,
another is a main decryption part.
public static void decryptFile(InputStream outFileIn, InputStream privKeyStream, char[] passPhrase, String outFileName) {
// ----- Decrypt the file
try {
ByteBuffer buf = ByteBuffer.allocate(1024 * 10);
byte[] read = new byte[1024];
while (outFileIn.read(read, 0, 1024) != -1) {
buf.put(read);
}
BASE64Encoder en = new BASE64Encoder();
String temp = en.encode(buf.array());
// System.out.println("Temp: " + temp);
byte[] newB = null;
BASE64Decoder en1 = new BASE64Decoder();
try {
newB = en1.decodeBuffer(temp);
} catch (Exception e) {
System.out.println("Exception: " + e);
}
ByteArrayInputStream bais = new ByteArrayInputStream(newB);
decryptIt(bais, privKeyStream, passPhrase, outFileName);
} catch (Exception e1) {
e1.printStackTrace();
}
}
This is full source code with latest version of pg Bouncy Castle Cryptography Library 1.58.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
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.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.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
//
public class FileEncryptTest {
private static File publicKeyFile = new File("resource/PGP1D0.pkr");
private static File privateKeyFile = new File("resource/PGP1D0.skr");
private static String privateKeyPassword = "passphrase";
private static final boolean isEncrypt = false;
public static void main(String[] args) {
Security.addProvider(new BouncyCastleProvider());
String outFileName = "resource/tile_doc.signed.in";
String recoverFile = "resource/tile_doc.out";
OutputStream out = null;
InputStream keyIn = null;
InputStream outFileIn = null;
String fileName = "resource/tile_doc.in";
PGPPublicKey encKey = null;
char[] passPhrase = privateKeyPassword.toCharArray();
boolean armor = false;
boolean withIntegrityCheck = true;
if (isEncrypt) {
try {
keyIn = new BufferedInputStream(new FileInputStream(privateKeyFile));
out = new BufferedOutputStream(new FileOutputStream(outFileName));
encKey = readPublicKeyFromCol(new FileInputStream(publicKeyFile));
//
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
signFile(fileName, keyIn, out, passPhrase, armor);
out = new BufferedOutputStream(new FileOutputStream(outFileName));
} catch (GeneralSecurityException | IOException | PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
encryptFile(outFileName, out, fileName, encKey, passPhrase, armor, withIntegrityCheck);
} else {
try {
keyIn = new BufferedInputStream(new FileInputStream(privateKeyFile));
outFileIn = new BufferedInputStream(new FileInputStream(outFileName));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decryptFile(outFileIn, keyIn, passPhrase, recoverFile);
}
}
static final KeyFingerPrintCalculator FP_CALC = new BcKeyFingerprintCalculator();
private static PGPPublicKey readPublicKeyFromCol(InputStream in) throws Exception {
PGPPublicKeyRing pkRing = null;
// PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(in,
// FP_CALC);
PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in), FP_CALC);
System.out.println("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();
System.out.println("Encryption key = " + key.isEncryptionKey() + ", Master key = " + key.isMasterKey());
if (key.isEncryptionKey())
return key;
}
}
return null;
}
public static void decryptFile(InputStream outFileIn, InputStream privKeyStream, char[] passPhrase, String outFileName) {
// ----- Decrypt the file
try {
ByteBuffer buf = ByteBuffer.allocate(1024 * 10);
byte[] read = new byte[1024];
while (outFileIn.read(read, 0, 1024) != -1) {
buf.put(read);
}
BASE64Encoder en = new BASE64Encoder();
String temp = en.encode(buf.array());
// System.out.println("Temp: " + temp);
byte[] newB = null;
BASE64Decoder en1 = new BASE64Decoder();
try {
newB = en1.decodeBuffer(temp);
} catch (Exception e) {
System.out.println("Exception: " + e);
}
ByteArrayInputStream bais = new ByteArrayInputStream(newB);
decryptIt(bais, privKeyStream, passPhrase, outFileName);
} catch (Exception e1) {
e1.printStackTrace();
}
}
private static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass)
throws IOException, PGPException, NoSuchProviderException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn), FP_CALC);
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
PBESecretKeyDecryptor secretKeyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(pass);
return pgpSecKey.extractPrivateKey(secretKeyDecryptor);
}
private static void decryptIt(InputStream in, InputStream keyIn, char[] passwd, String filename) throws Exception {
in = PGPUtil.getDecoderStream(in);
try {
PGPObjectFactory pgpF = new PGPObjectFactory(in, FP_CALC);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
//
// the first object might be a PGP marker packet.
//
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;
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
System.out.println("pbe id=" + pbe.getKeyID());
sKey = findSecretKey(keyIn, pbe.getKeyID(), passwd);
}
if (sKey == null) {
throw new IllegalArgumentException("secret key for message not found.");
}
// InputStream clear = pbe.getDataStream(sKey, "BC");
InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
PGPObjectFactory plainFact = new PGPObjectFactory(clear, FP_CALC);
Object message = plainFact.nextObject();
if (message instanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) message;
PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream(), FP_CALC);
message = pgpFact.nextObject();
}
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(filename));
if (message instanceof PGPLiteralData) {
PGPLiteralData ld = (PGPLiteralData) message;
InputStream unc = ld.getInputStream();
int ch;
while ((ch = unc.read()) >= 0) {
bout.write(ch);
}
} else if (message instanceof PGPOnePassSignatureList) {
throw new PGPException("encrypted message contains a signed message - not literal data.");
} else {
throw new PGPException("message is not a simple encrypted file - type unknown.");
}
bout.flush();
bout.close();
if (pbe.isIntegrityProtected()) {
if (!pbe.verify()) {
System.err.println("message failed integrity check");
} else {
System.err.println("message integrity check passed");
}
} else {
System.err.println("no message integrity check");
}
} catch (PGPException e) {
System.err.println(e);
if (e.getUnderlyingException() != null) {
e.getUnderlyingException().printStackTrace();
}
}
}
private static void encryptFile(String outFileName, OutputStream out, String fileName, PGPPublicKey encKey,
char[] passPhrase, boolean armor, boolean withIntegrityCheck) {
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
System.out.println("creating comData...");
// get the data from the original file
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);
try {
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
comData.close();
} catch (IOException e) {
}
}
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck)
.setSecureRandom(new SecureRandom()).setProvider("BC"));
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
byte[] bytes = bOut.toByteArray();
OutputStream cOut;
try {
cOut = encGen.open(out, bytes.length);
cOut.write(bytes);
} catch (IOException | PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
encGen.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 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.
*/
static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input),
new JcaKeyFingerprintCalculator());
//
// 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.");
}
private static void signFile(String fileName, InputStream keyIn, OutputStream out, char[] pass, boolean armor)
throws GeneralSecurityException, IOException, PGPException {
if (armor) {
out = new ArmoredOutputStream(out);
}
PGPSecretKey pgpSec = readSecretKey(keyIn);
PGPPrivateKey pgpPrivKey = pgpSec
.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
PGPSignatureGenerator sGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC"));
sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
BCPGOutputStream bOut = new BCPGOutputStream(out);
InputStream fIn = new BufferedInputStream(new FileInputStream(fileName));
byte[] buf = new byte[1024];
int len;
while ((len = fIn.read(buf)) > 0) {
sGen.update(buf, 0, len);
}
//int ch;
//while ((ch = fIn.read()) >= 0) {
// sGen.update((byte) ch);
//}
fIn.close();
sGen.generate().encode(bOut);
if (armor) {
out.close();
}
out.close();
bOut.close();
}
}
Finally, the public/private key file generate with rsa.
I borrowed the code from RSAKeyPairGenerator.java.
The source as follows
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.SignatureException;
import java.util.Date;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
public class FileEncDec {
private static File publicKeyFile = new File("resource/PGP1D0.pkr");
private static File privateKeyFile = new File("resource/PGP1D0.skr");
private static String privateKeyPassword = "passphrase";
private static String identity = "tommybee";
private static boolean isAll = true;
private static void exportKeyPair(OutputStream secretOut, OutputStream publicOut, KeyPair pair, String identity,
char[] passPhrase, boolean armor)
throws IOException, InvalidKeyException, NoSuchProviderException, SignatureException, PGPException {
if (armor) {
secretOut = new ArmoredOutputStream(secretOut);
}
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1);
PGPKeyPair keyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, pair, new Date());
PGPSecretKey secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, keyPair, identity, sha1Calc, null,
null, new JcaPGPContentSignerBuilder(keyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1),
new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.CAST5, sha1Calc).setProvider("BC")
.build(passPhrase));
secretKey.encode(secretOut);
secretOut.close();
if (armor) {
publicOut = new ArmoredOutputStream(publicOut);
}
PGPPublicKey key = secretKey.getPublicKey();
key.encode(publicOut);
publicOut.close();
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
if (isAll) {
FileOutputStream out1 = new FileOutputStream(privateKeyFile);
FileOutputStream out2 = new FileOutputStream(publicKeyFile);
exportKeyPair(out1, out2, kp, identity, privateKeyPassword.toCharArray(), true);
} else {
FileOutputStream out1 = new FileOutputStream(privateKeyFile);
FileOutputStream out2 = new FileOutputStream(publicKeyFile);
exportKeyPair(out1, out2, kp, identity, privateKeyPassword.toCharArray(), false);
}
}
}
I hope this helps you.
Regards,
Here is the error I have got when run my Encode & Decode Class.
javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:365)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at RSAEncDecDemo.decryptData(RSAEncDecDemo.java:64)
at RSAEncDecDemo.main(RSAEncDecDemo.java:47)
java.lang.NullPointerException
at java.lang.String.<init>(String.java:556)
at RSAEncDecDemo.decryptData(RSAEncDecDemo.java:70)
at RSAEncDecDemo.main(RSAEncDecDemo.java:47)
Here is the source code of RSAEncDecDemo.java class file.
public class RSAEncDecDemo {
private static final String PUBLIC_KEY_FILE = "lk.public.key";
private static final String PRIVATE_KEY_FILE = "lk.private.key";
#SuppressWarnings("restriction")
public static void main(String[] args) throws IOException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
writeStringkey(PUBLIC_KEY_FILE,new BASE64Encoder().encode(publicKey.getEncoded()));
writeStringkey(PRIVATE_KEY_FILE,new BASE64Encoder().encode(privateKey.getEncoded()));
String demoString = "123346";
RSAEncDecDemo rsa = new RSAEncDecDemo();
String decrypted = rsa.decryptData(demoString);
String msisdn = decrypted.substring(0,decrypted.indexOf("|"));
} catch (Exception e) {
e.printStackTrace();
}
}
private String decryptData(String strData) throws IOException {
byte[] data = DatatypeConverter.parseHexBinary(strData);
byte[] descryptedData = null;
try {
PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
descryptedData = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return new String(descryptedData);
}
#SuppressWarnings("restriction")
public PrivateKey readPrivateKeyFromFile(String fileName)throws IOException, NoSuchAlgorithmException,InvalidKeySpecException {
String publicK = readStringKey(fileName);
byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicK);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePrivate(keySpec);
}
public PrivateKey readPrivateKeyFromFileold(String fileName)throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(new File(fileName));
ois = new ObjectInputStream(fis);
BigInteger modulus = (BigInteger) ois.readObject();
BigInteger exponent = (BigInteger) ois.readObject();
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(rsaPrivateKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
ois.close();
if (fis != null) {
fis.close();
}
}
}
return null;
}
public static void writeStringkey(String fileName, String data) {
try {
FileWriter out = new FileWriter(new File(fileName));
out.write(data);
out.close();
} catch (IOException e) {
}
}
public static String readStringKey(String fileName) {
BufferedReader reader = null;
StringBuffer fileData = null;
try {
fileData = new StringBuffer(2048);
reader = new BufferedReader(new FileReader(fileName));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
} catch (Exception e) {
} finally {
if (reader != null) {
reader = null;
}
}
return fileData.toString();
}
}
Where is mistaken point.? Decryption part is give that error.
Whole class uploaded here
LINK TO SOURCE CODE
-Thanks
In principle a ciphertext should be indistinguishable from random. That said, ciphers do place constraints on the domain (size and possible values). In the case of RSA PKCS#1 - which is the default mode for "RSA" within the Oracle provider - the output must be precisely the key size (in bytes). Furthermore, the value must be smaller than the modulus.
Now assume that you've just shown us a demo value (because the exception doesn't match the input) and the size of the ciphertext is correct. In that case you would get an unpadding exception when either:
the private key doesn't match the public key used;
the wrong padding mode (e.g. OAEP) was used to create the ciphertext;
the ciphertext was altered (e.g. due to an invalid conversion to a string).
You would have to try until you find the culprit, without the required information we cannot test this for you.
result variable in the below class is always returning false though I am using the correct signature file and the public key.
public class VeriGen {
static FileInputStream fin;
public static void main(String args[]) throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyStore msCertStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
msCertStore.load(null, null);
X509Certificate c = ((X509Certificate) msCertStore.getCertificate("Software View Certificate Authority"));
PublicKey pubKey = c.getPublicKey();
File file = new File("C:\\Users\\mayooranM\\Desktop\\SignatureVerificationTest\\ProcessExplorer.zip");
fin = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()];
File signedData = new File(
"C:\\Users\\mayooranM\\Desktop\\SignatureVerificationTest\\SignedProcessExplorer.sig");
fin = new FileInputStream(signedData);
byte signedContent[] = new byte[(int) signedData.length()];
boolean result = verifySig(fileContent, pubKey, signedContent);
System.out.println("result is : " + result);
}
public static boolean verifySig(byte[] data, PublicKey key, byte[] sig) throws Exception {
Signature signer = Signature.getInstance("SHA1WithRSA", "BC");
signer.initVerify(key);
signer.update(data);
return (signer.verify(sig));
}
}
Below is the code I used to sign the file.
public class SigGen {
static final String KEYSTORE_FILE = "C:\\Users\\mayooranM\\Desktop\\x.509-sample-keys-and-certificates\\generation-tool\\swviewca.p12";
static final String KEYSTORE_INSTANCE = "PKCS12";
static final String KEYSTORE_PWD = "swviewcastoresecret";
static final String KEYSTORE_ALIAS = "swviewca";
static FileInputStream fin = null;
public static void main(String args[]) throws Exception {
Security.addProvider(new BouncyCastleProvider());
File file = new File("C:\\Users\\mayooranM\\Desktop\\SignatureVerificationTest\\ProcessExplorer.zip");
fin = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()];
KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray());
Key key = ks.getKey(KEYSTORE_ALIAS, KEYSTORE_PWD.toCharArray());
// Sign
PrivateKey privKey = (PrivateKey) key;
byte[] signedData = signData(fileContent, privKey);
FileOutputStream fos = new FileOutputStream(
"C:\\Users\\mayooranM\\Desktop\\SignatureVerificationTest\\SignedProcessExplorer.sig");
fos.write(signedData);
fos.close();
}
public static byte[] signData(byte[] data, PrivateKey key) throws Exception {
Signature signer = Signature.getInstance("SHA1WithRSA", "BC");
signer.initSign(key);
signer.update(data);
return (signer.sign());
}
}
What am I doing wrong here? Please advice.
In the code you posted, it looks like you're never actually reading the file; fin is assigned but never used, and the signedContentand fileContent arrays are created, but never filled.
I have the following pieces of code:
Globals
public static PublicKey pubKey;
public static PrivateKey privKey;
public static Cipher cip;
Main
public static void main(String[] args) throws Exception {
//Generate the keys
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
cip = Cipher.getInstance("RSA/ECB/NoPadding");
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream("public.key");
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream("private.key");
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
//Get the public and private keys out of their files
getPubAndPrivateKey();
//Check if the keys gotten out of the files are the same as the generated files (this returns truetrue)
System.out.print(publicKey.equals(pubKey));
System.out.print(privateKey.equals(privKey));
byte[] text = "This is my super secret secret".getBytes();
encryptToFile("encrypted.txt", text );
decryptToFile("encrypted.txt", "decrypted.txt");
}
Getting the keys from the files
private static void getPubAndPrivateKey() throws IOException, Exception {
// Read Public Key.
File filePublicKey = new File("public.key");
FileInputStream fis = new FileInputStream("public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File("private.key");
fis = new FileInputStream("private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
pubKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
privKey = keyFactory.generatePrivate(privateKeySpec);
}
Encrypting
public static void encryptToFile(String fileName, byte[] data)
throws IOException {
try {
cip.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cip.doFinal(data);
String encryptedData = cipherData.toString();
BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
out.write(encryptedData);
out.close();
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
}
}
Decrypting
private static void decryptToFile(String string, String string2)
throws Exception {
try {
File encryptedFile = new File("encrypted.txt");
byte[] encrypted = getContents(encryptedFile).getBytes();
cip = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cip.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherData = cip.doFinal(encrypted);
String decryptedData = cipherData.toString();
BufferedWriter out = new BufferedWriter(new FileWriter(
"decrypted.txt"));
out.write(decryptedData);
out.close();
} catch (Exception e) {
throw e;
}
}
Things I already checked
The data used in the decryption is the same as in the encrypted file
The generated keys are the same as the ones gotten from the file
The encryption and decryption both don't give errors
Results
Original string:
My super secret secret
The encryption results in:
[B#1747b17
The decryption results in:
[B#91a4fb
If you print out a byte array via toString() method you are getting a value that is totally independent of the content.
Therefore the values [B#1747b17 [B#91a4fb are just garbage that does not tell you anything.
If you want to print the content of a byte array convert it to Base64 or hex-string.
System.out.println(new sun.misc.BASE64Encoder().encode(myByteArray));
A hex string can be generated by using org.apache.commons.codec.binary.Hex from Apache Commons Codec library.
I agree with the above answer.
I would like to add that in your case, you can simply use FileOutputStream, write the bytes to a file -
For example:
public static void encryptToFile(String fileName, byte[] data)
throws IOException {
FileOutputStream out = null;
try {
cip.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cip.doFinal(data);
out = new FileOutputStream(fileName);
out.write(cipherData);
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ex) {
}
}
}
}