DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How Java Apps Litter Beyond the Heap
  • A Maven Story
  • Penetration Testing: A Comprehensive Guide
  • 10 Ways To Keep Your Java Application Safe and Secure

Trending

  • Driving DevOps With Smart, Scalable Testing
  • Memory Leak Due to Time-Taking finalize() Method
  • System Coexistence: Bridging Legacy and Modern Architecture
  • Proactive Security in Distributed Systems: A Developer’s Approach
  1. DZone
  2. Data Engineering
  3. Data
  4. Encryption, Part 3: Hybrid Encryption

Encryption, Part 3: Hybrid Encryption

Looking for the best of both worlds when it comes to symmetric and public/private key encryption?

By 
Bipin Patwardhan user avatar
Bipin Patwardhan
·
May. 21, 19 · Presentation
Likes (1)
Comment
Save
Tweet
Share
15.2K Views

Join the DZone community and get the full member experience.

Join For Free

In part one of the series, I covered the topic of symmetric encryption (SE). While in part two, I covered public/ private key encryption, also known as public key encryption (PKE). The limitation of symmetric encryption is that the key used for encryption and decryption is one and the same. Hence, the key needs to be kept a secret. PKE overcomes the problem of key sharing by using two keys — one private and one public. To share a message, it is typically encrypted using the public key. Then, the private key counterpart of the public key can be used to decrypt the message. Thus, PKE achieves security.

But using PKE for large messages is very difficult for two reasons. The first reason is that the longer text that can be encrypted in one go has to be less than the length of the key used for encryption. The second reason is that PKE is more time consuming, compared to symmetric encryption. The third reason why PKE is not used for encrypting long messages is that after encryption, the length of the encrypted text is much larger than the length of the original text.

Hybrid Encryption

Hybrid encryption — a mashup of SE and PKE — provides an elegant solution that preserves the speed of SE, while maintaining the security and exchange flexibility of PKE. We also do not end up increasing the length of the text message to be encrypted.

The idea of hybrid encryption is quite simple. Instead of using PKE to encrypt the text, we use SE to encrypt the message. Then, they maintain the secrecy of the key, and we encrypt the key using PKE. The steps of hybrid encryption are:

  1. Generate a symmetric key. The symmetric key needs to be kept a secret.
  2. Encrypt the data using the secret symmetric key.
  3. The person to whom we wish to send a message will share her public key and keep the private key a secret.
  4. Encrypt the symmetric key using the public key of the receiver.
  5. Send the encrypted symmetric key to the receiver.
  6. Send the encrypted message text.
  7. The receiver decrypts the encrypted symmetric key using her private key and gets the symmetric key needed for decryption.
  8. The receiver uses the decrypted symmetric key to decrypt the message, getting the original message.

In the hybrid method, the data to be encrypted is not limited by the length of the encryption key. Additionally, the encrypted symmetric key is secure because it is encrypted using the public key of the receiver. Even if the encrypted data and the encrypted key are intercepted by another person, they will not be able to get the original data as long as the private key is maintained as a secret.

Sample Application in Java

Below is example Java code that illustrates the HE method:

package edh;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class EncDeHybrid
{
  // Symmetric encryption algorithms supported - AES, RC4, DES
  // encryption algorithm - DES, key size - 56
  protected static String DEFAULT_ENCRYPTION_ALGORITHM = "AES";
  protected static int DEFAULT_ENCRYPTION_KEY_LENGTH = 256;

  // key encryption algorithms supported - RSA, Diffie-Hellman, DSA
  // key pair generator - RSA: keyword - RSA, key size: 1024, 2048
  // key pair generator - Diffie-Hellman: keyword i DiffieHellman, key size - 1024
  // key pair generator - DSA: keyword - DSA, key size: 1024
  // NOTE: using asymmetric algorithms other than RSA needs to be worked out 
  protected static String DEFAULT_KEY_ENCRYPTION_ALGORITHM = "RSA";
  protected static int DEFAULT_KEY_ENCRYPTION_KEY_LENGTH = 1024;
  protected static String DEFAULT_TRANSFORMATION = "RSA/ECB/PKCS1Padding";

  protected SecretKey mSecretKey;
  protected String mEncryptionAlgorithm, mKeyEncryptionAlgorithm, mTransformation;
  protected int mEncryptionKeyLength, mKeyEncryptionKeyLength;
  protected PublicKey mPublicKey;
  protected PrivateKey mPrivateKey;

  EncDeHybrid()
  {
    mSecretKey = null;
    mEncryptionAlgorithm = EncDeHybrid.DEFAULT_ENCRYPTION_ALGORITHM;
    mEncryptionKeyLength = EncDeHybrid.DEFAULT_ENCRYPTION_KEY_LENGTH;
    mKeyEncryptionAlgorithm = EncDeHybrid.DEFAULT_KEY_ENCRYPTION_ALGORITHM;
    mKeyEncryptionKeyLength = EncDeHybrid.DEFAULT_KEY_ENCRYPTION_KEY_LENGTH;
    mPublicKey = null;
    mPrivateKey = null;
    mTransformation = EncDeHybrid.DEFAULT_TRANSFORMATION;
  }

  EncDeHybrid(String encAlgo, int encKeyLength, String keyEncAlgo, int keyEncKeyLength, String transformation)
  {
    mSecretKey = null;
    mEncryptionAlgorithm = encAlgo;
    mEncryptionKeyLength = encKeyLength;
    mKeyEncryptionAlgorithm = keyEncAlgo;
    mKeyEncryptionKeyLength = keyEncKeyLength;
    mTransformation = transformation;
  }

  public static BigInteger keyToNumber(byte[] byteArray)
  {
    return new BigInteger(1, byteArray);
  }

  public SecretKey getSecretKey()
  {
    return mSecretKey;
  }

  public byte[] getSecretKeyAsByteArray()
  {
    return mSecretKey.getEncoded();
  }

  // get base64 encoded version of the key
  public String getEncodedSecretKey()
  {
    String encodedKey = Base64.getEncoder().encodeToString(mSecretKey.getEncoded());
    return encodedKey;
  }

  // decode the base64 encoded string
  public SecretKey getDecodedSecretKey(String encodedKey, String algo)
  {
    byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
    // rebuild key using SecretKeySpec
    SecretKey originalKey = null;

    if ( null == algo ) {
      originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, mEncryptionAlgorithm);
    } else {
      originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, algo);
    }

    return originalKey;
  }

  public PublicKey getPublicKey()
  {
    return mPublicKey;
  }

  public byte[] getPublicKeyAsByteArray()
  {
    return mPublicKey.getEncoded();
  }

  public String getEncodedPublicKey()
  {
    String encodedKey = Base64.getEncoder().encodeToString(mPublicKey.getEncoded());
    return encodedKey;
  }

  public PrivateKey getPrivateKey()
  {
    return mPrivateKey;
  }

  public byte[] getPrivateKeyAsByteArray()
  {
    return mPrivateKey.getEncoded();
  }

  public String getEncodedPrivateKey()
  {
    String encodedKey = Base64.getEncoder().encodeToString(mPrivateKey.getEncoded());
    return encodedKey;
  }

  // step 1 -- generate the symmetric key
  public void generateSymmetricKey()
  {
    KeyGenerator generator;
    try {
      generator = KeyGenerator.getInstance(mEncryptionAlgorithm);
      generator.init(mEncryptionKeyLength);

      mSecretKey = generator.generateKey();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }

  // step 2 -- encrypt the plain text
  public byte[] encryptText(String textToEncrypt)
  {
    byte[] byteCipherText = null;

    try {
      Cipher encCipher = Cipher.getInstance(mEncryptionAlgorithm);
      encCipher.init(Cipher.ENCRYPT_MODE, mSecretKey);
      byteCipherText = encCipher.doFinal(textToEncrypt.getBytes());
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    }

    return byteCipherText;
  }

  // step 3 -- encrypt the secret key using key encryption algorithm
  public byte[] encryptSecretKey()
  {
    byte[] encryptedKey = null;
    try {
      KeyPairGenerator kpg = KeyPairGenerator.getInstance(mKeyEncryptionAlgorithm);
      kpg.initialize(mKeyEncryptionKeyLength);

      KeyPair keyPair = kpg.generateKeyPair();

      mPublicKey = keyPair.getPublic();
      mPrivateKey = keyPair.getPrivate();

      Cipher cipher = Cipher.getInstance(mTransformation);
      cipher.init(Cipher.PUBLIC_KEY, mPublicKey);

      encryptedKey = cipher.doFinal(mSecretKey.getEncoded());
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    }

    return encryptedKey;
  }

  public byte[] encryptSecretKeyNoTransformation()
  {
    byte[] encryptedKey = null;
    try {
      KeyPairGenerator kpg = KeyPairGenerator.getInstance(mKeyEncryptionAlgorithm);
      kpg.initialize(mKeyEncryptionKeyLength);

      KeyPair keyPair = kpg.generateKeyPair();

      mPublicKey = keyPair.getPublic();
      mPrivateKey = keyPair.getPrivate();

      Cipher cipher = Cipher.getInstance(mTransformation);
      cipher.init(Cipher.PUBLIC_KEY, mPublicKey);

      encryptedKey = cipher.doFinal(mSecretKey.getEncoded());
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    }

    return encryptedKey;
  }

  // step 4 -- send across the encrypted text and the encrypted secret key

  // setp 5 -- decrypt secret key
  public byte[] decryptSecretKey(byte[] encryptedSecretKey)
  {
    byte[] decryptedKey = null;

    try {
      Cipher cipher = Cipher.getInstance(mTransformation);
      cipher.init(Cipher.PRIVATE_KEY, mPrivateKey);

      decryptedKey = cipher.doFinal(encryptedSecretKey);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    }

    return decryptedKey;
  }

  // step 6 -- Decrypt the cipher using decrypted symmetric key
  public String decryptText(byte[] decryptedKey, byte[] encryptedText)
  {
    String decryptedPlainText = null;

    try {
      SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey.length, mEncryptionAlgorithm);
      Cipher aesCipher2 = Cipher.getInstance(mEncryptionAlgorithm);
      aesCipher2.init(Cipher.DECRYPT_MODE, originalKey);
      byte[] bytePlainText = aesCipher2.doFinal(encryptedText);
      decryptedPlainText = new String(bytePlainText);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    }

    return decryptedPlainText;
  }
}


And the main block to call this is given below:

package edh;

import javax.crypto.SecretKey;

public class Main
{
  public static void main(String[] args)
  {
    String plainText = "Hello World, Hybrid Encryption style";
    System.out.println("plainText: '" + plainText + "'");

    EncDeHybrid ed = new EncDeHybrid();

    ed.generateSymmetricKey();
    System.out.println("secret key: '" + EncDeHybrid.keyToNumber(ed.getSecretKey().getEncoded()).toString() + "'" );

    String strEncodedSecretKey = ed.getEncodedSecretKey();
    System.out.println("encoded secret key: '" + strEncodedSecretKey + "'" );
    SecretKey sk = ed.getDecodedSecretKey(strEncodedSecretKey, null);
    System.out.println("decoded secret key: '" + EncDeHybrid.keyToNumber(sk.getEncoded()).toString() + "'" );

    byte[] encryptedSecretKey = ed.encryptSecretKey();
    System.out.println("encrypted secret key: '" + EncDeHybrid.keyToNumber(encryptedSecretKey).toString() + "'" );

    byte[] encryptedText = ed.encryptText(plainText);
    System.out.println("encrypted text: '" + EncDeHybrid.keyToNumber(encryptedText).toString() + "'" );

    byte[] decryptedSecretKey = ed.decryptSecretKey(encryptedSecretKey);
    System.out.println("decrypted secret key: '" + EncDeHybrid.keyToNumber(decryptedSecretKey).toString() + "'" );

    String decryptedText = ed.decryptText(decryptedSecretKey, encryptedText);
    System.out.println("decryptedText: '" + decryptedText + "'");
  }
}


That's all on hybrid encryption. Happy encrypting!

Receiver (information theory) Data (computing) security Java (programming language) application Blocks Mashup (web application hybrid)

Opinions expressed by DZone contributors are their own.

Related

  • How Java Apps Litter Beyond the Heap
  • A Maven Story
  • Penetration Testing: A Comprehensive Guide
  • 10 Ways To Keep Your Java Application Safe and Secure

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!