Tuesday, February 26, 2019

PGP hybrid cryptosystem (symmetric + asymmetric for the symmetric key)


Cryptography


There are five primary functions of cryptography today:
  • Privacy/confidentiality: Ensuring that no one can read the message except the intended receiver.
  • Authentication: The process of proving one's identity.
  • Integrity: Assuring the receiver that the received message has not been altered in any way from the original.
  • Non-repudiation: A mechanism to prove that the sender really sent this message.
  • Key exchange: The method by which crypto keys are shared between sender and receiver. 

There are several ways of classifying cryptographic algorithms. Based on the number of keys that are employed for encryption and decryption and further defined by their application and use. The three types of algorithms are :
  • Private/Secret Key Cryptography (SKC )/ Conventional cryptography: Uses a single key for both encryption and decryption; also called symmetric encryption. Primarily used for privacy and confidentiality.
  • Public Key Cryptography (PKC): Uses one key for encryption and another for decryption; also called asymmetric encryption. Primarily used for authentication, non-repudiation, and key exchange.
  • Hash Functions: Uses a mathematical transformation to irreversibly "encrypt" information, providing a digital fingerprint. Primarily used for message integrity.
Due to the above characteristics, symmetric and asymmetric algorithms are sometimes used in a hybrid approach. Asymmetric ciphers are characteristically used for identity authentication performed via digital signatures & certificates, for the distribution of symmetric bulk encryption key, non-repudiation services and for key agreement. Symmetric ciphers are used for bulk encryption of data due to their fast speed.

How PGP will improve the performance in compare with Asymmetric Cryptography like RSA
  • RSA isn't really built to encrypt large pieces of plaintext. Each RSA "round" can encrypt 117 bytes of data, and to encrypt more, you'd have to use some chaining mode. Currently, this means extra overhead, slowness (remember, RSA is pretty slow), and security uncertainty (RSA-chaningMode hasn't been scrutinized as other types of encryption schemes). 
  • Not only is RSA too slow to use on bulk data, but it even has certain weaknesses that can be exploited in some special  cases of particular kinds of messages that are fed to the RSA cipher, even for large keys.
  • These special cases can be avoided by using the hybrid approach of using RSA to encrypt random session keys for a conventional cipher, like PGP does. So the bottom line is this: Using pure RSA on bulk data is the wrong approach, period. It's too slow, it's not stronger, and may even be weaker.
  • The additional mechanisms performed by PGP (compression and random key generation) rather than any difference in the performance of the encryption algorithms themselves.
  • We also note that Diffie-Hellman marginly outperforms RSA, which is directly in contradiction with earlier findings where RSA was significantly faster. This second point might be the result of the initialisation phase of RSA being more costly and so on a very small amount of data (the randomly generated key), it becomes less efficient than Diffie-Hellman.

PGP : Hybrid Crypto System (Symmetric & Asymmetric) 


PGP combines some of the best features of both conventional and public key cryptography. PGP is a hybrid cryptosystem. PGP encryption or Pretty Good Privacy encryption, is a data encryption computer program that gives cryptographic privacy and authentication for online communication. It is often used to encrypt and decrypt texts, emails, and files to increase the security of emails. PGP encryption uses a mix of data compression, hashing, and public-key cryptography. It also uses symmetric and asymmetric keys to encrypt data that is transferred across networks. It combines features of private and public key cryptography. Each step uses a different algorithm, and each public key is associated with a username and an email address




When plaintext is encrypted with PGP, it first compresses the plaintext. Data compression saves transmission time, disk space, and reinforces cryptographic security. Most cryptanalysis methods exploit patterns that are found in the plaintext. However, the asymmetry of PGP encryption allows for authentication. After public keys have been traded among partners, the private keys are used to digitally sign the encrypted content. This allows the decryptor to confirm the sender.

PGP generates a symmetric key to encrypt data which is protected by the asymmetric key.

  • PGP actually implements a solution such that symmetric encryption is used to encrypt data, and asymmetric encryption is used to encrypt the key.
  • Since asymmetric encryption can't encrypt anything larger than its own key size. This bundle is commonly referred to as "asymmetric encryption" even though it's a hybrid model.

Difference between RSA and PGP

  • PGP is a software suite of encryption algorithms and the ability to encrypt emails, files, etc. RSA is a specific algorithm for encryption and digital signatures.


Difference between AES and PGP

  • The encryption PGP offers is just as strong as that of AES, but it adds the additional security that prevents anyone with just the public key from being able to decrypt data that was previously encrypted with it.
  • AES is fast and works best in closed systems and large databases; PGP should be used when sharing information across an open network, but it can be slower and works better for individual files. 
How PGP works

When a user encrypts plaintext with PGP, PGP first compresses the plaintext.  Compression reduces these patterns in the plaintext, thereby greatly enhancing resistance to cryptanalysis. (Files that are too short to compress or which don't compress well aren't compressed.)


PGP Encryption

 
PGP then creates a session key, which is a one-time-only secret key. This key is a random number generated from the random movements of your mouse and the keystrokes you type. This session key works with a very secure, fast conventional encryption algorithm to encrypt the plaintext; the result is ciphertext. Once the data is encrypted, the session key is then encrypted to the recipient's public key. This public key-encrypted session key is transmitted along with the ciphertext to the recipient.



PGP Decryption


Decryption works in the reverse. The recipient's copy of PGP uses his or her private key to recover the temporary session key, which PGP then uses to decrypt the conventionally-encrypted ciphertext.



The combination of the two encryption methods combines the convenience of public key encryption with the speed of conventional encryption. Conventional encryption is about 1, 000 times faster than public key encryption. Public key encryption in turn provides a solution to key distribution and data transmission issues. Used together, performance and key distribution are improved without any sacrifice in security.

Difference between PGP , OpenPGP and GPG



PGP (Pretty Good Privacy) : 
  • PGP encryption uses a serial combination of hashing, data compression, symmetric-key cryptography, and, finally,public-key cryptography to keep data secure; each step uses one of several supported algorithms. Each public key is bound to a user name and/or an e-mail address. This process can be used to encrypt text files, emails, data files, directories, and disk partitions.
  • The Pretty Good Privacy software originally written by Phil Zimmermann, and now owned by Symantec.At first it was written as copyrighted freeware under the Gnu Public License.
  • Later, PGP was upgraded and made into a propriety program. The rights for this program are traded around. The reason for this upgrade was legal defense costs and royalty issues related to the export laws of the USA.
  • PGP uses the RSA algorithm and the IDEA encryption algorithm. PGP does not use the DES as its conventional single-key algorithm to encrypt messages. Instead, PGP uses a different conventional single-key block encryption algorithm, called IDEA(tm). By default, PGP uses IDEA.


OpenPGP

The formats for keys, encrypted messages and message signatures defined by PGP.  These have now been formalised as the OpenPGP standard , which is where GPG comes in.


GPG (GNU Privacy Guard)

  • The GPG software is an independent implementation of the OpenPGP standards.GPG is a re-write or upgrade of PGP. It is royalty free because it is not patented. GPG is more compatible than the original PGP with OpenPGP.
  • It does not use the IDEA encryption algorithm. This is to make it completely free.It uses the NIST AES, Advanced Encryption Standard. The main reason for this change is that AES costs less than IDEA and is considered more secure.
  • GPG uses CAST5 by default.For GnuPG 1.0 default is CAST5,for gnupg-1.4.23 is AES128, for GnuPG 2.0.14 it is 3DES, for GnuPG 2.1 it is AES-128. The default for gnupg-2.1.18 is AES256
  • You can force GnuPG to use AES256 for encryption with
            [root@sjena]$ gpg --cipher-algo AES256
  • GPG was developed by Werner Koch and released in 1999 as an alternative to Symantec's software suite of encryption tools. It's available as a free software download and is based on the OpenPGP standards established by the IETF.
  • This ensures that PGP is interoperable with Symantec's PGP tools, as well as OpenPGP standards, and can open and unencrypt any PGP and OpenPGP standards file.
Note:
  • You can use GPG to exchange encrypted messages with anyone using other OpenPGP implementations,  including Symantec's PGP.

IS PGP and GPG keys are 100% compatible in all use cases (100% interchangeable)

  • Depending on the PGP version , there are known interoperability problems.
  • PGP 2.x normally uses IDEA which is not supported by GnuPG as it is patented.

Check the default symmetric ciphers used in GPG

[root@sjena]$ gpg --verbose –symmetric

gpg: using cipher 3DES
gpg: writing to stdout


Check all supported ciphers used in GPG



[root@sjena]$ gpg --verbose --version

gpg (GnuPG) 2.0.14
libgcrypt 1.4.5
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA
Cipher: 3DES (S2), CAST5 (S3), BLOWFISH (S4), AES (S7), AES192 (S8),AES256 (S9), TWOFISH (S10), CAMELLIA128 (S11), CAMELLIA192 (S12),CAMELLIA256 (S13)
Hash: MD5 (H1), SHA1 (H2), RIPEMD160 (H3), SHA256 (H8), SHA384 (H9),SHA512 (H10), SHA224 (H11) Compression: Uncompressed (Z0), ZIP (Z1), ZLIB (Z2), BZIP2 (Z3)

System Requirements
  • Linux
  • GPG version 1.4.5
Confirm GPG version
The GPG version must be version 1.4.5.
Enter the following command to display the version:
[root@sjena]$ gpg –help
gpg (GnuPG) 2.0.14
libgcrypt 1.4.5
Copyright (C) 2009 Free Software Foundation, Inc.


Start the key generation process
Enter the following command to start generating your key:
[root@sjena]$ gpg –gen-key

Select the type of key

Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1

Select the key size

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Select the expiration time
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

Enter user name and email
GnuPG needs to construct a user ID to identify your key.
Real name: Sridhar Jena
Email address: sjena@java2depth.com
Comment: JAVA2DEPTH PGP TEST ENV.
You selected this USER-ID:
"Sridhar Jena (JAVA2DEPTH PGP TEST ENV.) <sjena@java2depth.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
Enter passphrase to protect secret key
You need a Passphrase to protect your secret key.
Enter passphrase: J@v@2Depth
Repeat passphrase: J@v@2Depth

We need to generate a lot of random bytes.It is a good idea to perform some other action (type on the keyboard,move the mouse, utilize the disks) during the prime generation;this gives the random number generator a better chance to gain enough entropy.

You may see the following message. If you do, follow the instructions
and the key generation process will start automatically.

gpg: key AA21FF79 marked as ultimately trusted public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
pub 4096R/AA21FF79 2019-02-20
Key fingerprint = DB64 21D5 0B04 D521 CD06 C518 F9ED 33D4 AA21 FF79
uid Sridhar Jena (JAVA2DEPTH PGP TEST ENV.) <sjena@java2depth.com>
sub 4096R/DD9355EE 2019-02-20

Verify the keys are generated or not using below command
[root@sjena]$ gpg –list-keys

pub 4096R/AA21FF79 2019-02-20
uid Sridhar Jena (JAVA2DEPTH PGP TEST ENV.) <sjena@java2depth.com>
sub 4096R/DD9355EE 2019-02-20

Export public key using below command
[root@sjena]$ gpg --export -a sjena@java2depth.com > public.key

Export private key using below command
[root@sjena]$ gpg --export-secret-keys -a sjena@java2depth.com > private.key

Delete private key using below command
[root@sjena]$ gpg --delete-secret-keys sjena@java2depth.com
sec 4096R/AA21FF79 2016-07-20 Sridhar Jena (JAVA2DEPTH PGP TEST ENV.)
<sjena@java2depth.com>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

Delete public key using below command
[root@sjena]$ gpg --delete-keys sjena@java2depth.com
pub 4096R/AA21FF79 2016-07-20 Sridhar Jena (JAVA2DEPTH PGP TEST ENV.)
<sjena@java2depth.com>
Delete this key from the keyring? (y/N) y

PGP Encryption / Decryption Example

Plain Data : Hello - This is JAVA2DEPTH PGP Test
Public Key :
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.14 (GNU/Linux)
mQINBFePR3cBEADWUbCEJvZ8EWbtL8dj9abKAeiqdGWP/CbnmDyHzKE
FeEKWKc6SgSfrxLEBLTmYLghdM+bwCmHD7Vw6R88iCAnonuO1MQu2-
--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------
xJYleDbPtHgSXXyJNB/TOxWVJGQYktnkNPmYFPpJKUPgiwxLCQxGZS9fC
+hEvZBtiSgnwMPJsV1192GAdwzkHQ278CR87M5dWsoVGpQEO75AiTeJ
UJrIP+Y=Sx1V
-----END PGP PUBLIC KEY BLOCK-----

Encrypted Data :
hQIMA+dwi84+aNUXAQ//W3RwksB3wGPEMMkcqsIzErBNPntwLWp0o3ZFw9tfx+HBft
5R+lp/YRh7vkYf2VqJDjX48b71x18pdXGXTvWIG/aLOW1PYuTojo7BSFtc5wjslZaNoXP3
bD/Q3HpcgLUFJiU8/vIisQzkO8wRzPACY9dJ3j8Bu4cXA0lCLdKjxWi4JipBgwlkQXPdJax3h
n8WbYRPeLQhwnS/yJNG3YkcJkVRRDpfr8wnfBnf+Da7jtyYtxVfYufhB8xXot1oLri6dAOz
y6bi/DWncOSiS39gxEh8He6SaZZhawdn2nQm3O63O15lizlDxfnS8W8ClnNDJuY4qQey
8kvH5IT8jh4i4C+GOJNml1zMJGACvWh6lQzC1U//1yhs4wpZH1zO2ds9JOhOMSkpcky4
eSXAPxoNNn9IMEpAP1aE4ocj6181wnKw1eidHukL4AgRZs52rg9I4B/gXimDHrAKgKN0
WS8OrlOvzrUCp4v2pV0roolSlm/zx/SOmgs8h6kG9rGxDH7bd56UqzNrhQG+ipX8i06iL
d/2XO4PRrTf1AYltO+nHTWMfZKvzWdBRubElCr0+6Ol/N9b0CXyVhmVw9EjQsdM1+L
mH4gl1+OwG5DDPZSeQrU1dMzO8Cta1s25+H7obaIzw6g7c/QxcBU9IpVTbRR3piVRe
nmAgcUSwmCVG5T3N/nSUQFyrTeHEGH6bu/G/R2Ns00/I+OuR5NfI1ejgV7wEmlymXG
55ls/D9DUmT9Tox9vFeGn0UUU3KZKhU3iZaRF+4zcdBJ3eJYJ36WXQxModRsqcw===
yvAU


Private Key :
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v2.0.14 (GNU/Linux)
lQc+BFePR3cBEADWUbCEJvZ8EWbtL8dj9abKAeiqdGWP/CbnmDyHzKE
FeEKWKc6SgSfrxLEBLTmYLghdM+bwCmHD7Vw6R88iCAnonuO1MQu2-
-------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------
piwIcI1jqVRipqvdseWFwK2BVJGQYktnkNPmYFPpJKUPgiwxLCQxGZS9fC
+hEvZBtiSgnwMPJsV1192GAdwzkHQ278CR87M5dWsoVGpQEO75AiTeJ
UJrIP+Y=83JN
-----END PGP PRIVATE KEY BLOCK-----

Decrypted Data : Hello - This is JAVA2DEPTH PGP Test


Easy PGP encryption in Java with Bouncy Castle
  • Bouncy Castle is an open-source provider of encryption software. They have a clean room implementation of a Java SecurityProvider and a full PGP tools implementation, all entirely in Java, all free.
  • You can pull in the security provider and PGP implementation to your project with this maven dependency declaration:  
bcpg-jdk15on-1.52.jar
bcpkix-jdk15on-1.52.jar
bcprov-jdk15on-1.52.jar
  • Add these libraries into your java class path .
PGPFactory.java

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.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.bouncycastle.bcpg.ArmoredOutputStream;
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.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;



public class PGPFactory {

    private PGPPublicKey pgpPublicKey = null;
    private PGPSecretKeyRingCollection pgpSecretKeyRingCollection = null;
    private KeyFingerPrintCalculator fingerPrintCalculator = null;
    private char[] passphrase = null;
    private static PGPFactory pgpFactory = null;

    private PGPFactory() {
    }

    public static PGPFactory getInstance() {
        if (null == pgpFactory) {
            Security.addProvider(new BouncyCastleProvider());
            pgpFactory = new PGPFactory();
        }
        return pgpFactory;
    }

    /**
     * Load Public Key,Private Key,Passphrase
     */
    public void loadKeys(String pubKeyPath, String privKeyPath, String password) {
        FileInputStream pubKey = null;
        FileInputStream secKey = null;
        try {
            fingerPrintCalculator = new JcaKeyFingerprintCalculator();
            pubKey = new FileInputStream(pubKeyPath);
            pgpPublicKey = readPublicKey(pubKey);
            secKey = new FileInputStream(privKeyPath);
            pgpSecretKeyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(secKey), fingerPrintCalculator);
            passphrase = password.toCharArray();
        } catch (IOException ioException) {
            System.err.println("IOException in init: " + ioException.getMessage());
        } catch (PGPException pgpException) {
            System.err.println("PGPException in init: " + pgpException.getMessage());
        } finally {
            try {
                if (null != pubKey) {
                    pubKey.close();
                }
                if (null != secKey) {
                    secKey.close();
                }
            } catch (IOException ioException) {
                System.err.println("IOException in init: " + ioException.getMessage());
            }
        }
    }

    private PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws PGPException, NoSuchProviderException {
        PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
        if (pgpSecKey == null) {
            return null;
        }
        PBESecretKeyDecryptor secretKeyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(pass);
        return pgpSecKey.extractPrivateKey(secretKeyDecryptor);
    }

    /**
     * decrypt the passed in message stream
     * 
     * @param encrypted
     *            The message to be decrypted.
     * 
     * @return Clear text as a byte array. I18N considerations are not handled
     *         by this routine
     * @exception IOException
     * @exception PGPException
     * @exception NoSuchProviderException
     */

    private byte[] decrypt(byte[] encrypted) {
        byte[] returnBytes = null;
        InputStream inputStream = null;
        InputStream clear = null;
        InputStream unc = null;
        ByteArrayOutputStream out = null;
        try {
            inputStream = new ByteArrayInputStream(encrypted);
            inputStream = PGPUtil.getDecoderStream(inputStream);
            PGPObjectFactory pgpF = new PGPObjectFactory(inputStream, fingerPrintCalculator);
            PGPEncryptedDataList enc = null;
            Object object = pgpF.nextObject();
            if (object instanceof PGPEncryptedDataList) {
                enc = (PGPEncryptedDataList) object;
            } else {
                enc = (PGPEncryptedDataList) pgpF.nextObject();
            }
            Iterator it = enc.getEncryptedDataObjects();
            PGPPrivateKey sKey = null;
            PGPPublicKeyEncryptedData pbe = null;
            while (sKey == null && it.hasNext()) {
                pbe = (PGPPublicKeyEncryptedData) it.next();
                sKey = findSecretKey(pgpSecretKeyRingCollection, pbe.getKeyID(), passphrase);
            }
            if (sKey == null) {
                throw new IllegalArgumentException("secret key for message not found.");
            }
            PublicKeyDataDecryptorFactory decryptorFactory = new BcPublicKeyDataDecryptorFactory(sKey);
            clear = pbe.getDataStream(decryptorFactory);
            PGPObjectFactory pgpFact = new PGPObjectFactory(clear, fingerPrintCalculator);
            PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();
            pgpFact = new PGPObjectFactory(cData.getDataStream(), fingerPrintCalculator);
            PGPLiteralData literalData = (PGPLiteralData) pgpFact.nextObject();
            unc = literalData.getInputStream();
            out = new ByteArrayOutputStream();
            int ch;
            while ((ch = unc.read()) >= 0) {
                out.write(ch);
            }
            returnBytes = out.toByteArray();
        } catch (IOException ioException) {
            System.err.println("IOException in decrypt: " + ioException.getMessage());
        } catch (PGPException pgpException) {
            System.err.println("PGPException in decrypt: " + pgpException.getMessage());
        } catch (NoSuchProviderException noSuchProviderException) {
            System.err.println("NoSuchProviderException in decrypt: " + noSuchProviderException.getMessage());
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
                if (null != clear) {
                    clear.close();
                }
                if (null != unc) {
                    unc.close();
                }
            } catch (IOException exception) {
                System.err.println("IOException in decrypt: " + exception.getMessage());
            }
        }
        return returnBytes;
    }

    private void decryptFile(InputStream in, OutputStream out) {
        InputStream unc = null;
        InputStream clear = null;
        try {
            in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);
            PGPObjectFactory pgpF = new PGPObjectFactory(in, fingerPrintCalculator);
            PGPEncryptedDataList enc;

            Object object = pgpF.nextObject();
            if (object instanceof PGPEncryptedDataList) {
                enc = (PGPEncryptedDataList) object;
            } else {
                enc = (PGPEncryptedDataList) pgpF.nextObject();
            }
            Iterator it = enc.getEncryptedDataObjects();
            PGPPrivateKey sKey = null;
            PGPPublicKeyEncryptedData pbe = null;

            while (sKey == null && it.hasNext()) {
                pbe = it.next();
                sKey = findSecretKey(pgpSecretKeyRingCollection, pbe.getKeyID(), passphrase);
            }

            if (sKey == null) {
                throw new IllegalArgumentException("Secret key for message not found.");
            }

            clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
            PGPObjectFactory plainFact = new PGPObjectFactory(clear, fingerPrintCalculator);
            Object message = plainFact.nextObject();

            if (message instanceof PGPCompressedData) {
                PGPCompressedData cData = (PGPCompressedData) message;
                PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream(), fingerPrintCalculator);
                message = pgpFact.nextObject();
            }

            if (message instanceof PGPLiteralData) {
                PGPLiteralData ld = (PGPLiteralData) message;
                unc = ld.getInputStream();
                int ch;
                while ((ch = unc.read()) >= 0) {
                    out.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.");
            }

            if (pbe.isIntegrityProtected()) {
                if (!pbe.verify()) {
                    throw new PGPException("Message failed integrity check");
                }
            }
        } catch (IOException ioException) {
            System.err.println("IOException in decryptFile: " + ioException.getMessage());
        } catch (NoSuchProviderException suchProviderException) {
            System.err.println("NoSuchProviderException in decryptFile: " + suchProviderException.getMessage());
        } catch (PGPException pgpException) {
            System.err.println("PGPException in decryptFile: " + pgpException.getMessage());
        } finally {
            try {
                if (null != clear) {
                    clear.close();
                }
                if (null != unc) {
                    unc.close();
                }
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException ioException) {
                System.err.println("IOException in decryptFile: " + ioException.getMessage());
            }
        }
    }

    /**
     * Simple PGP encryptor between byte[].
     * 
     * @param clearData
     *            The test to be encrypted
     * @param fileName
     *            File name. This is used in the Literal Data Packet (tag 11)
     *            which is really inly important if the data is to be related to
     *            a file to be recovered later. Because this routine does not
     *            know the source of the information, the caller can set
     *            something here for file name use that will be carried. If this
     *            routine is being used to encrypt SOAP MIME bodies, for
     *            example, use the file name from the MIME type, if applicable.
     *            Or anything else appropriate.
     * 
     * @param withIntegrityCheck
     * @param armor
     * 
     * @return encrypted data.
     * @exception IOException
     * @exception PGPException
     * @exception NoSuchProviderException
     */

    private byte[] encrypt(byte[] clearData, String fileName, boolean armor,boolean withIntegrityCheck) {
        ByteArrayOutputStream encOut = null;
        OutputStream out = null;
        ByteArrayOutputStream bOut = null;
        OutputStream cos = null;
        OutputStream pOut = null;
        OutputStream cOut = null;
        try {
            if (fileName == null) {
                fileName = PGPLiteralData.CONSOLE;
            }
            encOut = new ByteArrayOutputStream();
            out = encOut;
            if (armor) {
                out = new ArmoredOutputStream(out);
            }
            bOut = new ByteArrayOutputStream();
            PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);
            cos = comData.open(bOut);
            PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
            pOut = lData.open(cos, PGPLiteralData.BINARY, fileName, clearData.length, new Date());
            pOut.write(clearData);
            lData.close();
            comData.close();

            BcPGPDataEncryptorBuilder builder = new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5);
            builder.setSecureRandom(new SecureRandom());
            builder.setWithIntegrityPacket(withIntegrityCheck);

            PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(builder);
            PGPKeyEncryptionMethodGenerator method = new JcePublicKeyKeyEncryptionMethodGenerator(pgpPublicKey);
            encryptedDataGenerator.addMethod(method);
            byte[] bytes = bOut.toByteArray();
            cOut = encryptedDataGenerator.open(out, bytes.length);
            cOut.write(bytes);
            encryptedDataGenerator.close();
        } catch (IOException ioException) {
            System.err.println("IOException in encrypt: " + ioException.getMessage());
        } catch (PGPException pgpException) {
            System.err.println("PGPException in encrypt: " + pgpException.getMessage());
        } finally {
            try {
                if (null != cos) {
                    cos.close();
                }
                if (null != cOut) {
                    cOut.close();
                }
                if (null != out) {
                    out.close();
                }
                if (null != encOut) {
                    encOut.close();
                }

                if (null != bOut) {
                    bOut.close();
                }
                if (null != pOut) {
                    pOut.close();
                }

            } catch (IOException ioException) {
                System.err.println("IOException in encrypt: " + ioException.getMessage());
            }
        }
        return encOut.toByteArray();
    }

    private void encryptFile(OutputStream out, String fileName, boolean armor, boolean withIntegrityCheck) {
        OutputStream cOut = null;
        ByteArrayOutputStream bOut = null;
        try {
            if (armor) {
                out = new ArmoredOutputStream(out);
            }
            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.setSecureRandom(new SecureRandom());
            dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);

            PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
            encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(pgpPublicKey));

            byte[] bytes = bOut.toByteArray();
            cOut = encryptedDataGenerator.open(out, bytes.length);
            cOut.write(bytes);
            encryptedDataGenerator.close();
        } catch (IOException ioException) {
            System.err.println("IOException in encryptFile: " + ioException.getMessage());
        } catch (PGPException pgpException) {
            System.err.println("PGPException in encryptFile: " + pgpException.getMessage());
        } finally {
            try {
                if (null != cOut) {
                    cOut.close();
                }
                if (null != out) {
                    out.close();
                }
                if (null != bOut) {
                    bOut.close();
                }
            } catch (IOException ioException) {
                System.err.println("IOException in encryptFile: " + ioException.getMessage());
            }
        }

    }

    private PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {
        in = PGPUtil.getDecoderStream(in);
        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in, fingerPrintCalculator);
        Iterator rIt = pgpPub.getKeyRings();
        while (rIt.hasNext()) {
            PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
            Iterator kIt = kRing.getPublicKeys();
            while (kIt.hasNext()) {
                PGPPublicKey k = (PGPPublicKey) kIt.next();
                if (k.isEncryptionKey()) {
                    return k;
                }
            }
        }
        throw new IllegalArgumentException("Can't find encryption key in key ring.");
    }

    public String encrypt(String clearData) {
        String encryptedData = "";
        try {
            byte[] encryptedBytes = encrypt(clearData.getBytes(), null, true, true);
            String encryptedText = new String(encryptedBytes);
            List encryptedTextLines = Arrays.asList(encryptedText.split("\n\n"));
            String encryptedParagraph = encryptedTextLines.get(1);
            List encryptedLines = Arrays.asList(encryptedParagraph.split("\n"));

            for (int i = 0; i < encryptedLines.size() - 1; i++) {
                encryptedData += encryptedLines.get(i);
            }
        } catch (Exception exception) {
            System.err.println("Exception in encrypt: " + exception.getMessage());
        }
        return encryptedData;
    }

    public String decrypt(String encryptedData) {
        byte[] decrypted = decrypt(encryptedData.getBytes());
        return new String(decrypted);
    }

    public void encryptFile(String plainFilePath, String encryptFilePath) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(encryptFilePath);
            encryptFile(out, plainFilePath, false, true);
        } catch (IOException ioException) {
            System.err.println("IOException in encryptFile: " + ioException.getMessage());
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
            } catch (IOException ioException) {
                System.err.println("IOException in encryptFile: " + ioException.getMessage());
            }
        }
    }

    public void decryptFile(String encryptFilePath, String decryptFilePath) {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream(encryptFilePath);
            out = new FileOutputStream(decryptFilePath);
            decryptFile(in, out);
        } catch (IOException ioException) {
            System.err.println("IOException in decryptFile: " + ioException.getMessage());
        } finally {
            try {
                if (null != in) {
                    in.close();
                }
                if (null != out) {
                    out.close();
                }
            } catch (IOException ioException) {
                System.err.println("IOException in decryptFile: " + ioException.getMessage());
            }
        }
    }

}

TestTextMain.java
public class TestTextMain {
    public static void main(String[] args) {
        PGPFactory pgpFactory = PGPFactory.getInstance();
        pgpFactory.loadKeys("/home/sjena/public.key", "/home/sjena/private.key", "J@v@2Depth");

        String original = "Sridhar Jena";
        System.out.println("PLAIN DATA: " + original);

        String encryptedData = pgpFactory.encrypt(original);
        System.out.println("Encrypted Data: " + encryptedData);

        String decrypted = pgpFactory.decrypt(encryptedData);
        System.out.println("Decrypted Data :" + new String(decrypted));

    }
}
TestFileMain.java
public class TestFileMain {
    public static void main(String[] args) {
        PGPFactory pgpFactory = PGPFactory.getInstance();
        pgpFactory.loadKeys("/home/sjena/public.key", "/home/sjena/private.key", "J@v@2Depth");

        String DE_INPUT = "/home/sjena/encrypt.pgp";
        String DE_OUTPUT = "/home/sjena/decrypt.txt";

        String E_INPUT = "/home/sjena/plain.txt";
        String E_OUTPUT = "/home/sjena/encrypt.pgp";

        pgpFactory.encryptFile(E_INPUT, E_OUTPUT);
        pgpFactory.decryptFile(DE_INPUT, DE_OUTPUT);

    }
}

3 comments: