I am trying to decrypt a file downloaded as ByteArrayOutputStream from Azure Storage.
I have a stream of type ByteArrayOutputStream.
How can I decrypt it and return decrypted ByteArrayOutputStream.?
I have tried using CipherOutputStream, but I'm not sure how to use it.
Below is the code (snippet) I am using to encrypt the file before uploading
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8")));
blob.upload(new CipherInputStream(file.getInputStream(), cipher), file.getSize());
Below is my code:
public ByteArrayOutputStream download(String fileName, Long id) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encrypkey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8")));
CipherOutputStream output = null;
container = getBlobClient().getContainerReference("container" + id.toString());
CloudBlockBlob blob = container.getBlockBlobReference(fileName);
if (blob.exists()) {
blob.download(os);
//output = new CipherOutputStream(outputStream, cipher);
} else {
logger.info("File does not exists on azure container");
}
} catch (StorageException e) {
logger.error("StorageException : {}" + e.getLocalizedMessage(), e);
} catch (Exception e) {
logger.error("Exception : {}" + e.getLocalizedMessage(), e);
}
return os;
}
First create the CipherOutputStream, then download the blob into that output:
output = new CipherOutputStream(os, cipher);
blob.download(output);
Related
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.
In my application i have Decrypt file with AES256 and CBC .
i have written below codes, to check if file exists.
But when run application it shows me an error and not can open my file!
I used Log.e to show files's path and it shows me this path. but it says can not open file!
My code :
private SecureRandom r;
private byte[] _iv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
r = new SecureRandom();
_iv = new byte[16];
r.nextBytes(_iv);
String inputFile = getRootDirPath(context) + "/"+bookName;
String outPutFile = getRootDirPath(context) + "/BookFile_716798_decrypt3.html";
File file = new File(inputFile);
if (file.exists()) {
try {
decrypt(inputFile, encryptionPassword, outPutFile, "");
Log.e("DecryptLog", "0");
} catch (IOException e) {
e.printStackTrace();
Log.e("DecryptLog", "1 : " + e.getMessage());
Log.e("DecryptLog", "\nPath : " + inputFile);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Log.e("DecryptLog", "2 : " + e.getMessage());
} catch (NoSuchPaddingException e) {
e.printStackTrace();
Log.e("DecryptLog", "3 : " + e.getMessage());
} catch (InvalidKeyException e) {
e.printStackTrace();
Log.e("DecryptLog", "4 : " + e.getMessage());
}
} else {
Toast.makeText(context, "Not", Toast.LENGTH_SHORT).show();
}
}
public String getRootDirPath(Context context) {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File file = ContextCompat.getExternalFilesDirs(context.getApplicationContext(),
null)[0];
return file.getAbsolutePath();
} else {
return context.getApplicationContext().getFilesDir().getAbsolutePath();
}
}
private void decrypt(String path, String password, String _initVector, String outPath)
throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(outPath);
byte[] key = (password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
try {
cipher.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(_iv));
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
After run application show me this error :
2020-08-01 08:03:59.324 28560-28560/com.app.appE/DecryptLog: 1 : : open failed: ENOENT (No such file or directory)
2020-08-01 08:03:59.324 28560-28560/com.app.app E/DecryptLog: Path : /storage/emulated/0/Android/data/com.app.app/files/BookFile_716798.html
In my application I want to download an HTML file from server, then decrypt this file and show into webView!
The backend developer uses this library for encrypt file from server: https://github.com/soarecostin/file-vault
I wrote the code below, but when decrypting a file, it shows an error in Logcat and doesn't decrypt this file!
My code:
encryptionPassword = "7BOF%aZQMpfJ#2wUS*S6!#K+ZB$Sz+J0";
String inputFile = FileUtils.getDirPath(this) + "/BookFile_716798.html";
String outPutFile = FileUtils.getDirPath(this) + "/BookFile_716798_decrypt.html";
try {
decrypt(inputFile, encryptionPassword, outPutFile);
Log.e("DecryptLog", "0");
} catch (IOException e) {
e.printStackTrace();
Log.e("DecryptLog", "1");
Log.e("DecryptLog", "" + e.getMessage());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Log.e("DecryptLog", "2");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
Log.e("DecryptLog", "3");
} catch (InvalidKeyException e) {
e.printStackTrace();
Log.e("DecryptLog", "4");
}
private void decrypt(String path, String password, String outPath)
throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(outPath);
byte[] key = (password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
This message is shown in logCat:
2020-07-31 21:52:39.881 1367-1367/com.app.app E/DecryptLog: 1
2020-07-31 21:52:39.881 1367-1367/com.app.appE/DecryptLog: javax.crypto.BadPaddingException: pad block corrupted
How can I fix it?
I got a task to perform encryption and decryption of some large amount of files which are consisting of Audio,Video,and some html,swf files. And for this the code I am using works fine in my system. But when I am trying to execute the same code on server using java RMI it throws java.lang.OutOfMemoryError Java heap space.
Please suggest your views how to solve this memory leak issue.
Following is the code that I am using:
public static void performEncryption(String baseFolderLocation)
{
String key = "This is a secret";
System.out.println("Started Doing Encrypting...");
List<File> filenames = getAllfilesInFolder(baseFolderLocation, new ArrayList<File>());
int processedFilesCount = 0;
for (File file : filenames) {
try {
Crypto.fileProcessor(Cipher.ENCRYPT_MODE, key, file.getAbsoluteFile(), file.getAbsoluteFile());
} catch (Exception ex) {
// ex.printStackTrace();
}
processedFilesCount++;
}
System.out.println("Ended Encrypting...");
}
static void fileProcessor(int cipherMode, String key, File inputFile, File outputFile) {
try {
Key secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static List<File> getAllfilesInFolder(String directoryName, ArrayList<File> files) {
File directory = new File(directoryName);
// get all the files from a directory
File[] fList = directory.listFiles();
for (File file : fList)
{
if (file.isFile())
{
files.add(file);
}
else if (file.isDirectory())
{
getAllfilesInFolder(file.getAbsolutePath(), files);
}
}
return files;
}
Can you try to increase java heap memory of your server using -Xmx option?
How can we store the KEY in a key file for AES encryption using java so that the key file can be used for decryption purpose.
private static void storeKey(SecretKey key){
byte[] keyb = key.getEncoded();
FileOutputStream keyfos;
try {
File file = new File(generateKeyFilesPath);
if (!file.exists()) {
file.createNewFile();
}
keyfos = new FileOutputStream(file);
keyfos.write(keyb);
keyfos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static SecretKeySpec getKey(String generateKeyFilesPath){
SecretKeySpec key = null;
try {
File keyFile = new File(path);
FileInputStream stream = new FileInputStream(keyFile);
byte[] bytesArray = new byte[(int) keyFile.length()];
stream.read(bytesArray);
stream.close();
key = new SecretKeySpec(bytesArray, "AES");
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
Unable to decrypt the cipher using the stored key(file),