I trying to encrypt a .tar using .pgp encryption technique , i have key value(which is again not a file)which i have to use to encrypt the .tar file. The key value is a string (i.e. keyVal="xxxxx").I am taking the reference from the below URL which is there in the github, and is referenced by many users.
https://github.com/matthewmccullough/encryption-jvm-bootcamp/blob/master/bc-pgp/src/main/java/com/ambientideas/cryptography/KeyBasedFileProcessorUtil.java
This this example i want to encrypt the .tar file which i have in the location
../myTarLocation in my code
public static void encryptFile(
OutputStream out,
String fileName,
PGPPublicKey encKey,
boolean armor,
boolean withIntegrityCheck)
throws IOException, NoSuchProviderException
{
if (armor)
{
out = new ArmoredOutputStream(out);
}
try
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(), "BC");
cPk.addMethod(encKey);
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
out.close();
}
catch (PGPException e)
{
System.err.println(e);
if (e.getUnderlyingException() != null)
{
e.getUnderlyingException().printStackTrace();
}
}
}
But i can't understand where i shall use the keyVal which i have , and how i will encrypt the .tar file into a .tar.pgp file. .Can anyone please help me.
Related
I'm trying to write an encrypted file that will be decrypted using gpg and will be writing lines incrementally instead of in one chunk. I've generated the keys in GnuPG and am using the public key to encrypt. Here's the method I'm using to encrypt:
public static byte[] encrypt(byte[] clearData, PGPPublicKey encKey,
String fileName,boolean withIntegrityCheck, boolean armor)
throws IOException, PGPException, NoSuchProviderException {
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedDataGenerator.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
// we want to generate compressed data. This might be a user option
// later,
// in which case we would pass in bOut.
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_192).setSecureRandom(new SecureRandom()));
cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
And I have a small prototype test class to use that method like this:
PGPPublicKey pubKey = PGPEncryptionTools.readPublicKeyFromCol(new FileInputStream(appProp.getKeyFileName()));
byte[] encryptbytes = PGPEncryptionTools.encrypt("\nthis is some test text".getBytes(), pubKey, null, true, false);
byte[] encryptbytes2 = PGPEncryptionTools.encrypt("\nmore test text".getBytes(), pubKey, null, true, false);
FileOutputStream fos = new FileOutputStream("C:/Users/me/workspace/workspace/spring-batch-project/resources/encryptedfile.gpg");
fos.write(encryptbytes);
fos.write(encryptbytes2);
fos.flush();
fos.close();
So this creates encryptedfile.gpg, but when I go to GnuPG to decrypt the file, it works but it only outputs the first line "this is some test text".
How can I modify this code to be able to encrypt both lines and have GnuPG decrypt them?
You're producing multiple, independent OpenPGP messages each time calling your PGPEncryptionTools.encrypt(...) method. To only output a single OpenPGP message (which GnuPG also decrypt in a single run), write all plain text to a single stream (called pOut in your code) and do not close this before finally writing the last byte into the stream.
I'm writing module for server which will send e-mails. In client application user can add many receipients and each of them has its own public key. I want to encrypt attachments using multiple keys. For example if I add 3 receipients then attachments should be encrypted with 3 different public keys. I'm using bouncy castle to do that but it works only for the first public key in encryption process. I mean thath only the first person can decrypt using its own private key, for the rest it doesn't work.
My code for adding methods for each key looks like:
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
for (PGPPublicKey publicKey : publicKeys) {
encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));
}
Whole method looks like:
public File encryptFile(String fileName,
boolean armor,
boolean withIntegrityCheck) throws IOException,
NoSuchProviderException,
PGPException {
Security.addProvider(new BouncyCastleProvider());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData
= new PGPCompressedDataGenerator(PGPCompressedData.UNCOMPRESSED);
PGPUtil.writeFileToLiteralData(comData.open(bOut),
PGPLiteralData.BINARY,
new File(fileName));
comData.close();
BcPGPDataEncryptorBuilder dataEncryptor
= new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256);
dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
dataEncryptor.setSecureRandom(new SecureRandom());
PGPEncryptedDataGenerator encryptedDataGenerator
= new PGPEncryptedDataGenerator(dataEncryptor);
for (PGPPublicKey publicKey : publicKeys) {
encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));
}
byte[] bytes = bOut.toByteArray();
FileOutputStream localByteArrayOutputStream = new FileOutputStream(fileName);
Object localObject = localByteArrayOutputStream;
if (armor) {
localObject = new ArmoredOutputStream((OutputStream) localObject);
}
OutputStream localOutputStream = encryptedDataGenerator.open((OutputStream) localObject,
bytes.length);
localOutputStream.write(bytes);
localOutputStream.close();
return new File(fileName);
}
Can someone help me and tell me what I'm doing wrong?
Thank you for every help.
[EDIT]
This code works, I had problem in method loading multiple keys.
Well, I had the same problem a year later. I wish that you've solved yours. I'm writing my solution here just in case that someone else has similar issues.
Your encryption code doesn't have problem. The problem might be in the decryption. For an encrypted data object, the correct key should be found by using the key id stored with the object. My decryption process reads like the following:
private byte[] decryptWithKey(byte[] bytes, PGPSecretKey secKey, String pass)
throws PGPException, IOException {
PBESecretKeyDecryptor keyDec = new JcePBESecretKeyDecryptorBuilder(
new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build())
.setProvider("BC").build(pass.toCharArray());
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PGPPrivateKey privateKey = secKey.extractPrivateKey(keyDec);
PublicKeyDataDecryptorFactory dec1 =
new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(privateKey);
JcaPGPObjectFactory objFact = new JcaPGPObjectFactory(bytes);
PGPEncryptedDataList encList = (PGPEncryptedDataList) objFact.nextObject();
PGPPublicKeyEncryptedData encD = null;
for(Iterator<PGPPublicKeyEncryptedData> it = encList.iterator(); it.hasNext(); ) {
PGPPublicKeyEncryptedData end = it.next();
if (secKey.getKeyID() == end.getKeyID()) {
encD = end;
break;
}
}
assert encD != null: "Cannot find encrypted data with key: "
+ Long.toHexString(secKey.getKeyID());
InputStream in = encD.getDataStream(dec1);
byte[] buf = new byte[BufferSize];
for (int len; (len = in.read(buf)) >= 0; ) {
bout.write(buf, 0, len);
}
bout.close();
return bout.toByteArray();
}
The key is the for loop that finds the matching key for the encrypted object.
I am trying to develop a system that will decrypt a file then allows the authorized user to view it without saving the decrypted file. This is to ensure that the other user won't be able to open the decrypted file.
The following codes produced a file output.
public NewJFrame() {try{
String key = "squirrel123";
FileInputStream fis2 = newFileInputStream("encrypted.mui");
FileOutputStream fos2 = new FileOutputStream("decrypt.rar");
decrypt(key, fis2, fos2);
Desktop dk=Desktop.getDesktop();
File f = new File("decrypt.rar");
dk.open(f);
}
catch (Throwable e) {
JOptionPane.showMessageDialog(null, e);
}}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for SunJCE
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
How can I decrypt a file without using FileOutputStream then allows the authorized user to view it after the decryption?
If you don't want to write it to a Physical File, but just present the data instead, you may use a different writer then FileOutputStream.
For example, you can create a pair of PipedStream, decrypt and then read the result.
String key = "squirrel123";
FileInputStream fis2 = newFileInputStream("encrypted.mui");
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis);
decrypt(key, fis2, pis);
BufferedReader reader = new BufferedReader(new InputStreamReader(pis));
String line;
while( (line=reader.readLine()) != null ){
System.out.println(line);
}
I have a problem to read the file (for example *.zip) and encrypt it with 3DES, using secretKey which one generated from name of encrypted file.
Then I need to decrypt this file, and write it on HDD.
I tried to resolve thhis problem, but stuck when was decrypting file.
Here is code of encryptor
public class Encryptor {
private static String inputFilePath = "D:/1.txt";
public static void main(String[] args) {
FileOutputStream fos = null;
File file = new File(inputFilePath);
String keyString = "140405PX_0.$88";
String algorithm = "DESede";
try {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] fileByteArray = new byte[fileInputStream.available()];
fileInputStream.read(fileByteArray);
for (byte b : fileByteArray) {
System.out.println(b);
}
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
ObjectOutputStream objectOutputStream = new ObjectOutputStream
(new CipherOutputStream
(new FileOutputStream
("D:/Secret.file"), cipher));
objectOutputStream.writeObject(fileByteArray);
objectOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static SecretKey getKey(String message) throws Exception {
String messageToUpperCase = message.toUpperCase();
byte[] digestOfPassword = messageToUpperCase.getBytes();
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
return key;
}
}
And here is code of decryptor
public class Decryptor {
public static void main(String[] args) {
try {
File inputFileNAme = new File("d:/Secret.file");
FileInputStream fileInputStream = new FileInputStream(inputFileNAme);
FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
ObjectInputStream objectInputStream = new ObjectInputStream
(new CipherInputStream(fileInputStream, cipher));
System.out.println(objectInputStream.available());
while (objectInputStream.available() != 0) {
fileOutputStream.write((Integer) objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
}
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
objectInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static SecretKey getKey(String message) throws Exception {
String messageToUpperCase = message.toUpperCase();
byte[] digestOfPassword = messageToUpperCase.getBytes();
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
return key;
}
}
When i try to decrypt my file, i dont get anything in output file.
I tryed make debug, and saw, that objectInputStream.available() always contains 0.
Please tell me, how can I resolve this problem, and why it happens.
The usage
byte[] fileByteArray = new byte[fileInputStream.available()];
is specifically warned against in the Javadoc: " It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream."
Files should be processed a record or a buffer at a time.
The line:
fileInputStream.read(fileByteArray);
isn't guaranteed to fill the buffer. You have to check the return value: for -1, meaning end of file, or > 0, meaning the number of bytes that were actually transferred. See the Javadoc.
Similarly
while (objectInputStream.available() != 0) {
is not a valid test for end of stream. You should call readObject() until it throws EOFException.
As a quickfix, this works :
try {
File inputFileNAme = new File("d:/Secret.file");
FileInputStream fileInputStream = new FileInputStream(inputFileNAme);
FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
ObjectInputStream objectInputStream = new ObjectInputStream
(new CipherInputStream(fileInputStream, cipher));
System.out.println(objectInputStream.available());
fileOutputStream.write((byte[]) objectInputStream.readObject());
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
objectInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
What I did is remove the ".available() while loop" and remove the cast to Integer that was wrong.
I agree with EJP answer, especially regarding the use of .available().
You may also use http://www.jasypt.org/ that provides a more simple API to crytpo stuff.
I encrypted a text file in AES algorithm. I am not able to decrypt it. I used the same key and the whole process is running in the same method body.
At first, the input.txt file is being encrypted into encrypted.txt file. Then the decoder, decrypt the encrypted.txt into decrypted.txt
Here is the code. Thank you for your help.
public static void main(String[] args) throws IOException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException {
Scanner sc = new Scanner(System.in);
String filename = sc.nextLine();
sc.close();
System.out.println("The file requested is " + filename);
File file = new File(filename);
if (file.exists())
System.out.println("File found");
File to_b_encf = new File("encrypted.txt");
if (!to_b_encf.exists())
to_b_encf.createNewFile();
System.out.println("encrypting");
Cipher encipher = Cipher.getInstance("AES");
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecretKey key = keygen.generateKey();
encipher.init(Cipher.ENCRYPT_MODE, key);
FileOutputStream output = new FileOutputStream(to_b_encf);
FileInputStream input = new FileInputStream(filename);
CipherInputStream cis = new CipherInputStream(input, encipher);
int read;
while ((read = cis.read()) != -1) {
output.write(read);
output.flush();
}
input.close();
output.close();
System.out.println("done");
System.out.println("decrypting");
Cipher decipher = Cipher.getInstance("AES");//initiate a cipher for decryption
decipher.init(Cipher.DECRYPT_MODE, key);//decrypt the file
File sourcefile = new File("encrypted.txt");
File destfile = new File("decrypted.txt");
if (!destfile.exists())
destfile.createNewFile();
FileInputStream decf = new FileInputStream(sourcefile);
CipherInputStream c_decf = new CipherInputStream(decf,decipher);
FileOutputStream destf = new FileOutputStream(destfile);
cout = new CipherOutputStream(destf,decipher);
while ((read = c_decf.read()) != -1) {
cout.write(read);
cout.flush();
}
c_decf.close();
destf.close();
cout.close();
decf.close();
System.out.println("done");
}
You messed with InputStream, OutputStream and whatnot. I made a simplfied version of your code (no files, all in-memory I/O) that illustrates the main concepts:
public class EncDec {
public static void main(String[] args) throws IOException
, InvalidKeyException, NoSuchAlgorithmException
, NoSuchPaddingException {
final String MESSAGE = "I'm a secret message";
final Charset CHARSET = Charset.defaultCharset();
Cipher cipher = Cipher.getInstance("AES");
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
// Encrypt the message
InputStream plainIn = new ByteArrayInputStream(
MESSAGE.getBytes(CHARSET));
ByteArrayOutputStream encryptedOut = new ByteArrayOutputStream();
copy(plainIn, new CipherOutputStream(encryptedOut, cipher));
// Decrypt the message
cipher.init(Cipher.DECRYPT_MODE, key);
InputStream encryptedIn = new CipherInputStream(
new ByteArrayInputStream(encryptedOut.toByteArray()), cipher);
ByteArrayOutputStream plainOut = new ByteArrayOutputStream();
copy(encryptedIn, plainOut);
System.out.println(new String(plainOut.toByteArray(), CHARSET));
}
private static void copy(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[4096];
while ( in.read(buffer) > -1) {
out.write(buffer);
}
out.flush();
}
}
The Java I/O API is inspired by the decorator pattern. Encryption/decription libraries provide a decorator CipherInputStream for reading encrypted content and a decorator CipherOutputStream to encrypt a plain source and write it to the decorated output destination.
CipherInputStream c_decf = new CipherInputStream(decf,decipher);
FileOutputStream destf = new FileOutputStream(destfile);
cout = new CipherOutputStream(destf,decipher);
while ((read = c_decf.read()) != -1) {
cout.write(read);
cout.flush();
}
It looks like you're deciphering it twice.