Pgp sign+encrypt then decrypt+verify - java

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,

Related

Instance PGPPublicKey using a PGP Public Key Block

I have been given a PGP Public Key block with which I should encrypt a csv file. Using the BouncyCastle library, this is the method I am using:
public static void encryptFile(
OutputStream out,
String fileName,
PGPPublicKey encKey,
boolean armor,
boolean withIntegrityCheck)
throws IOException, NoSuchProviderException, PGPException {
Security.addProvider(new BouncyCastleProvider());
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
PGPUtil.writeFileToLiteralData(
comData.open(bOut),
PGPLiteralData.BINARY,
new File(fileName));
comData.close();
BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES);
dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
dataEncryptor.setSecureRandom(new SecureRandom());
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = encryptedDataGenerator.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
out.close();
}
I am not quite sure how can I provide the arguments to this method when it comes to PGPPublicKey. How can I instantiate this object given only my Key block?
Pass your key file(assuming you have your key as file) to this method and it will return PGPPublicKey
/** The fingerprint calculator to use whenever it is needed. */
static final KeyFingerPrintCalculator FP_CALC = new BcKeyFingerprintCalculator();
// Private class method readPublicKeyFromCol
private static PGPPublicKey readPublicKeyFromCol(InputStream in)
throws Exception {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(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;
}
!!!code is copied from sample code

blowfish key file illegal key size exception in linux tomcat deployment

I have a web app which is deployed on tomcat in both Linux and windows environment . Blowfish algo has been implemented for login password encryption/security check. It works fine in windows but throws illegal key size exception in linux. key file is packed with war
I have gone through multiple post but nothing really helped me.
generating key file
/** Generate a secret TripleDES encryption/decryption key */
KeyGenerator keygen = KeyGenerator.getInstance(SecurityConstant.BLOW_FISH_ALGO);
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = getBlowFishKeyPath();
FileOutputStream out = new FileOutputStream(keyPath);
Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawkey,StandardOpenOption.CREATE);
writer.close();
key comparision
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = SecurityUtil.hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = secretKey.getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, SecurityConstant.BLOW_FISH_ALGO);
// Create and initialize the encryption engine
cipher = Cipher.getInstance(SecurityConstant.BLOW_FISH_CBC_ZEROBYTE_ALGO, SecurityConstant.BC);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = SecurityUtil.bytesToHex(cipherText);// hexdecimal password stored in DB
} catch (Exception e) {
ExceptionLogger.logException(logger, e);
}
made it simpler to test
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SecTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
/** Generate a secret TripleDES encryption/decryption key */
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keygen = KeyGenerator.getInstance("Blowfish");
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = "/data2/key/BlowFish.key";
FileOutputStream out = null;
try {
out = new FileOutputStream(keyPath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawKey,StandardOpenOption.CREATE);
writer.close();
out.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
generateHexCode("a");
}
private static void generateHexCode(String pwd) {
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = readSecretKey().getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, "Blowfish");
// Create and initialize the encryption engine
cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = bytesToHex(cipherText);// hexdecimal password stored in DB
System.out.println("hex cipher is "+hexCipher);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String readSecretKey() {
byte[] rawkey = null;
String file ="";
// Read the raw bytes from the keyfile
String keyFile = "/data2/key/BlowFish.key";
String is = null;
try {
is = FileUtils.readFileToString(new File(keyFile),"UTF-8");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return is;
}
public static byte[] hexToBytes(String str) {
byte[] bytes = null;
if (str != null && str.length() >= 2) {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
bytes = buffer;
}
return bytes;
}
public static String bytesToHex(byte[] data) {
if (data == null) {
return null;
} else {
int len = data.length;
StringBuilder str = new StringBuilder();
for (int i = 0; i < len; i++) {
if ((data[i] & 0xFF) < 16) {
str = str.append("0").append(java.lang.Integer.toHexString(data[i] & 0xFF));
} else {
str.append(java.lang.Integer.toHexString(data[i] & 0xFF));
}
}
return str.toString().toUpperCase();
}
}
}
Made a simple program to test it out . This also runs fine on windows but fails on linux. any clue ?

javax.crypto.BadPaddingException: Given final block not properly padded after patching WebSphere

Well, this is not a new program and I haven't done any changes with problem parts.
My system admin has just patched the IBM WebSphere Application Server from 8.5.0.1 to 8.5.5.4.
I have encrypted numbers of files in the past. But after the upgrade has completed, I can't decrypt these files any more.
I am sure I am using the same method and key as they are all hard-coded in my program. And I haven't changed any related codes.
Here is the error.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Unknown Source)
at com.xxx.framework.core.common.util.CipherUtil.crypt(CipherUtil.java:175)
at com.xxx.framework.core.common.util.CipherUtil.decrypt(CipherUtil.java:102)
at com.xxx.framework.core.common.util.ZipCipherUtil.decryptUnzip(ZipCipherUtil.java:84)
at xxx(xxx.java:2894)
at xxx(xxx.java:748)
at xxx(xxx.java:727)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at yyy(ActionProxy.java:54)
I have deleted some parts as there are some sensitive business information
And this is the code
CipherUtil.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class CipherUtil {
private static String type = "AES";
private static final String HEXES = "0123456789ABCDEF";
public void encrypt(String srcFile, String destFile, String privateKey) throws GeneralSecurityException, IOException {
Key key = getKey(privateKey);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(mkdirFiles(destFile));
crypt(fis, fos, cipher);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
public void decrypt(String srcFile, String destFile, String privateKey) throws GeneralSecurityException, IOException {
Key key = getKey(privateKey);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(mkdirFiles(destFile));
crypt(fis, fos, cipher);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
private static Key getKey(String secret) throws GeneralSecurityException {
KeyGenerator kgen = KeyGenerator.getInstance(type);
kgen.init(128, new SecureRandom(secret.getBytes()));
SecretKey secretKey = kgen.generateKey();
return secretKey;
}
private static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException, GeneralSecurityException {
int blockSize = cipher.getBlockSize() * 1000;
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
if (inLength > 0)
outBytes = cipher.doFinal(inBytes, 0, inLength);
else
outBytes = cipher.doFinal();
out.write(outBytes);
}
public String encryptString(String srcString, String keyString) throws GeneralSecurityException {
Key key = getKey(keyString);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] coded = cipher.doFinal(srcString.getBytes());
return byteArrayToHexString(coded);
}
public String decryptString(String srcString, String keyString) throws GeneralSecurityException {
Key key = getKey(keyString);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = cipher.doFinal(hexStringToByteArray(srcString));
return new String(decoded);
}
private String byteArrayToHexString(byte[] raw)
{
if (raw == null)
{
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw)
{
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static byte[] hexStringToByteArray(String s) {
if (s == null || (s.length() % 2) == 1)
{
throw new IllegalArgumentException();
}
final char[] chars = s.toCharArray();
final int len = chars.length;
final byte [] data = new byte [len / 2];
for (int i=0; i<len; i+=2)
{
data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
}
return data;
}
}
Although I have mentioned "files", this method only treat the files as binary string to encrypt.
As I have DEV and UAT environment to test (DEV=8.5.5.4, UAT=8.5.0.1), I have tried to put the old encrypted files on DEV to the UAT. And they can decrypted under UAT.
Also I have tried to encrypt a new file under DEV and decrypt it, it is ok.
Is there anything I need to call my system admin to do?
I am only a programmer and I am not very skillful in server setup.
P.S. If there is anything to check, I am able to go into the WebSphere admin panel with admin right.
P.S.2. These codes are not written by me. Don't ask me what is the reason of these coding. By the way I have checked the codes and I can't find any issue with these codes, except some security worries but I am not sure.
Not sure if it is your problem or not, but this block:
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
is at least in principle incorrect. The in.read() could theoretically read less than the block length before reaching the end of file. The EOF condition is that in.read() returns -1. Maybe the update to the operating system has caused the FileInputStream to occasionally interrupt the read? In this case you will for the first time fall into the the inLength > 0 block of your code and try to decrypt a partial block which will definitely give the wrong result.
You can also temporarily disable PKCS5Padding by using NoPadding and see what the output of the encryption is.

How do you generate, sign and read digital signatures in java?

I am becoming intermediate java programmer. I have tried hard to find out how to sign and read digital signatures in java for a net program i have been working on. I have been able to generate private and public keys with the tutorial at http://docs.oracle.com/javase/tutorial/security/apisign/index.html but have not been able to do anything with them. Although I know how to generate keys i didn't put it in because i wasn't sure if i had done them correctly.
Here is a simplified version of my code:
Main class:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Main main = new Main();
Scanner s = new Scanner(System.in);
while (true) {
//This is where i added a command detector so that the program can be in one class
System.out.println("Choose a command from the following:\nGenerate keys\nSign message\nRead message");
String command = s.nextLine();
if (command.equalsIgnoreCase("Generate key")
|| command.equalsIgnoreCase("Generate")) {
/* The code for generating the keys is here */
File f = new File("C:\\Users\\spencer\\Documents\\Stack ex\\src\\app","public.key");
File fi = new File("C:\\Users\\spencer\\Documents\\Stack ex\\src\\app","private.key");
if(!f.isFile()||!fi.isFile()) {
Make make =new Make();
Make.main(args);
}
else{
try {
String path = "C:\\Users\\spencer\\Documents\\ds test 3\\src\\app";
KeyPair loadedKeyPair = main.LoadKeyPair(path, "DSA");
System.out.println("Key pair already exists!");
System.out.println("Loaded Key Pair:");
main.dumpKeyPair(loadedKeyPair);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
if (command.equalsIgnoreCase("Sign message")
|| command.equalsIgnoreCase("Sign")) {
long signature = 0;
System.out.println("What is your private key");
String pkey = s.nextLine();
long prkey = Long.parseLong(pkey);
System.out.println("What is you message");
String message = s.nextLine();
/* The code for signing the message goes here */
System.out.println("Signature:"+signature);
} else if (command.equalsIgnoreCase("Read message")
|| command.equalsIgnoreCase("Read")) {
String message = null;
System.out.println("What is the signature");
String sign = s.nextLine();
long signature = Long.parseLong(sign);
/* The code for reading the message goes here */
System.out.println(message);
}
}
}
private void dumpKeyPair(KeyPair keyPair) {
PublicKey pub = keyPair.getPublic();
System.out.println("Public Key: " + getHexString(pub.getEncoded()));
PrivateKey priv = keyPair.getPrivate();
System.out.println("Private Key: " + getHexString(priv.getEncoded()));
}
private String getHexString(byte[] b) {
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public KeyPair LoadKeyPair(String path, String algorithm)
throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException {
// Read Public Key.
File filePublicKey = new File(path + "/public.key");
FileInputStream fis = new FileInputStream(path + "/public.key");
byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
fis.read(encodedPublicKey);
fis.close();
// Read Private Key.
File filePrivateKey = new File(path + "/private.key");
fis = new FileInputStream(path + "/private.key");
byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
fis.read(encodedPrivateKey);
fis.close();
// Generate KeyPair.
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
encodedPublicKey);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return new KeyPair(publicKey, privateKey);
}
}
Make class:
import java.io.*;
import java.security.*;
import java.security.spec.*;
public class Make {
public static void main(String args[]) {
Make adam = new Make();
try {
String path = "C:\\Users\\spencer\\Documents\\Stack ex\\src\\app";
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(512);
KeyPair generatedKeyPair = keyGen.genKeyPair();
System.out.println("Generated Key Pair");
adam.dumpKeyPair(generatedKeyPair);
adam.SaveKeyPair(path, generatedKeyPair);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
private void dumpKeyPair(KeyPair keyPair) {
PublicKey pub = keyPair.getPublic();
System.out.println("Public Key: " + getHexString(pub.getEncoded()));
PrivateKey priv = keyPair.getPrivate();
System.out.println("Private Key: " + getHexString(priv.getEncoded()));
}
private String getHexString(byte[] b) {
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public void SaveKeyPair(String path, KeyPair keyPair) throws IOException {
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream(path + "/public.key");
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
fos = new FileOutputStream(path + "/private.key");
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
}
I need a little help with signing and reading the signature.

preCalculate file stream checksum

i'm trying to ensure an output File integrity in case of disk out of space , network problem ,or any anyException that might occur during the streaming to file process .
is there a way to precalculate the FileStream checkSum before writing to disk then check if the file was written properly.
it sounds a bit nonsensical for me , that a system validates the integrity of its own exported XML through checkSum , normaly it's the job of the other end to verify if the the consumed file lives up to the file produced by the other system .
but it's a requirement i have to implement.
her's the stream i write as a file :
String xmlTransfer ="";
File testFile = new File("testFile.xml");
InputStream in = new ByteArrayInputStream(xmlTransfer.getBytes("utf-8"));
FileOutputStream out = new FileOutputStream(testFile)
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.close();
in.close();
No, you can't figure out how much data will come from a stream in advance. That's simply not how streams are meant to work.
What you could do, if you are writing both ends of the code, is to first calculate the file size on the sending end and send that before sending the file contents itself.
The best way is to catch exception. If something go wrong an exception will be launched and you could remove the partially written file in this case.
A second way is to have a in-memory stream before writing down to the filesystem but it consumes memory.
A third way is to ensure the destination disk capacity (new File(path).getFreeSpace())
The MD5 check sounds too slow for me in regards of the question.
try this :
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.MessageDigest;
public class CheckSumFileTest
{
private File buildChecksumFile(File fileToCheck, String filePrefix, String checksumAlgorithm) throws Exception
{
String checksum = null;
File checksumFile = null;
String tempDir = System.getProperty("java.io.tmpdir");
try {
checksumFile = new File(tempDir, filePrefix+"."+ checksumAlgorithm.toLowerCase());
checksumFile.createNewFile();
checksumFile.deleteOnExit();
} catch (Exception e1) {
e1.printStackTrace();
throw e1;
}
FileWriter fw = null;
try {
checksum = checkSum(fileToCheck,checksumAlgorithm);
fw = new FileWriter(checksumFile);
fw.write(checksum);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
finally
{
if(fw !=null)
fw.close();
}
return checksumFile;
}
private static String checkSum(File file, String checksumAlgorithm) throws Exception
{
MessageDigest digest = MessageDigest.getInstance(checksumAlgorithm);
InputStream input = null;
StringBuffer sb = new StringBuffer();
try{
input = new FileInputStream(file);
byte[] buffer = new byte[8192];
do {
int read = input.read(buffer);
if(read <= 0)
break;
digest.update(buffer, 0, read);
} while(true);
byte[] sum = digest.digest();
for (int i = 0; i < sum.length; i++) {
sb.append(Integer.toString((sum[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(IOException io)
{
}finally{
if(input != null)
input.close();
}
return sb.toString();
}
private static String checkSumInStream(InputStream stream, String checksumAlgorithm) throws Exception
{
MessageDigest digest = MessageDigest.getInstance(checksumAlgorithm);
InputStream input = null;
StringBuffer sb = new StringBuffer();
try{
input = stream;
byte[] buffer = new byte[8192];
do {
int read = input.read(buffer);
if(read <= 0)
break;
digest.update(buffer, 0, read);
} while(true);
byte[] sum = digest.digest();
for (int i = 0; i < sum.length; i++) {
sb.append(Integer.toString((sum[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(IOException io)
{
}finally{
if(input != null)
input.close();
}
return sb.toString();
}
private boolean checkIntegrity(String targetFileName, String checksumFileName, String checksumAlgorithm) throws Exception
{
FileInputStream stream = null;
BufferedReader br = null;
InputStreamReader ipsr = null;
File checksumFile = null;
String checksumString="";
File targetFile = new File(targetFileName);
try{
checksumFile = new File(checksumFileName);
stream = new FileInputStream(checksumFile);
ipsr = new InputStreamReader(stream);
br = new BufferedReader(ipsr);
//In checksum file : only one line to read
checksumString = br.readLine();
}finally
{
if(br != null)
br.close();
if(ipsr != null)
ipsr.close();
if(stream != null)
stream.close();
}
if(checksumString.equals(checkSum(targetFile,checksumAlgorithm)))
{
return true;
}
else
{
return false;
}
}
/**
* #param args
*/
public static void main(String[] args)
{
String str = "Amine";
InputStream stream = new ByteArrayInputStream(str.getBytes());
//step1
try {
System.out.println(checkSumInStream(stream,"MD5"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//step2
File file = new File("c:/test.txt");
// if file doesnt exists, then create it
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
FileWriter fw;
BufferedWriter bw;
try {
fw = new FileWriter(file.getAbsoluteFile());
bw = new BufferedWriter(fw);
bw.write(str);
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(checkSum(file, "MD5"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Done");
}
}
You should check by MD5, not file size
You can calculate your MD5 while you're reading the stream.
See https://stackoverflow.com/a/304350/3230038
Then, after saving the file, you can generate the md5 again and compare
UPDATE - here's my more detailed idea for this. I am assuming that you just want to calculate the MD5 without having to bring the whole byte[] into memory. In this case, I think you have 2 options
calculate MD5 on the fly, as you're saving, then after saving, check md5 again (if you're on linux you can just use md5sum)
calculate MD5 in a first pass, then save the file in a second pass.
for example
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
public class MD5OnTheFly {
/**
* #param args
* #throws NoSuchAlgorithmException
* #throws IOException
*/
public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
long ini = System.currentTimeMillis();
File file = new File("/home/leoks/Downloads/VirtualBox-4.3.0.tar");
System.out.println("size:"+file.length());
InputStream is = new FileInputStream(file);
MessageDigest md = MessageDigest.getInstance("MD5");
DigestInputStream dis = new DigestInputStream(is, md);
IOUtils.copy(dis, new NullOutputStream());
byte[] digest = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(0xff & digest[i]);
if (hex.length() == 1)
hexString.append('0');
hexString.append(hex);
}
System.out.println(hexString);
long end = System.currentTimeMillis();
System.out.println(end-ini+" millis");
}
}
returns
410859520
dda81aea75a83b1489662c6bcd0677e4
1413 millis
and then
[leoks#home ~]$ md5sum /home/leoks/Downloads/VirtualBox-4.3.0.tar
dda81aea75a83b1489662c6bcd0677e4 /home/leoks/Downloads/VirtualBox-4.3.0.tar
[leoks#home ~]$

Categories

Resources