Public-key cryptography

Enigma

Using public-key cryptography anyone can encrypt messages using the public key, but only the holder of the paired private key can decrypt. Security depends on the secrecy of that private key.

This article describes the Java implementation of this approach based on the open source cryptography API for Java from Bouncy Castle.

Bouncy Castle provides a comprehensive but not easy to use API. I will show a utility class providing simple static methods for public-key encryption, which uses Bouncy Castle API internally. We use this class in verinice an open source Information security management system. You can download it from the verinice source code repository: SMIMEBasedEncryption.java. You also need classes from this package to compile SMIMEBasedEncryption.

Before using this class you have to enable unlimited strength encryption in the JRE. Go to the bottom of the JDK download page, download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6, and follow the instructioins in the archive.

Encrypt

SMIMEBasedEncryption has to methods to encrypt and decrypt data.
Static method encrypt:

  • Param byte[] unencryptedByteData – The data to encrypt. You have to transform your String or File to a byte Array before
  • Param File x509CertificateFile – Public key or certificate for encryption. I will describe below how to create this file with openssl.
  • Returns the encrypted data as byte array.

Source:

public static byte[] encrypt(byte[] unencryptedByteData, File x509CertificateFile) 
  throws Exception {

  byte[] encryptedMimeData = new byte[] {};
  X509Certificate x509Certificate = CertificateUtils.loadX509CertificateFromFile(x509CertificateFile);
  try {
      SMIMEEnvelopedGenerator generator = new SMIMEEnvelopedGenerator();
      generator.addKeyTransRecipient(x509Certificate);
		
      // create Base64 encoded mime body
      unencryptedByteData = Base64.encode(unencryptedByteData);
      MimeBodyPart unencryptedContent = SMIMEUtil.toMimeBodyPart(unencryptedByteData);

      // Encrypt the byte data and make a MimeBodyPart from it
      MimeBodyPart encryptedMimeBodyPart = generator.generate(unencryptedContent, SMIMEEnvelopedGenerator.AES256_CBC, BouncyCastleProvider.PROVIDER_NAME);

      // Finally get the encoded bytes from the MimeMessage and return them
      ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
      encryptedMimeBodyPart.writeTo(byteOutStream);
      encryptedMimeData = byteOutStream.toByteArray();
  } catch (Exception e) {
        throw new EncryptionException("There was a problem during the en- or decryption process. See the stacktrace for details.", e);
  }
  return encryptedMimeData;
}

Decrypt

Static method decrypt:

  • Param byte[] encryptedByteData – The encrypted data. Reed this from a file or database before.
  • Param File x509CertificateFile – Public key or certificate for decryption. I will describe below how to create this file with openssl.
  • Param File privateKeyPemFile – Private key for decryption. I will describe below how to create this file with openssl.
  • String privateKeyPassword – The password for the private key. This param is optional since not every private key is password protected. It might be null.
  • Returns the decrypted data as byte array.

Source:

public static byte[] decrypt(
  byte[] encryptedByteData, 
  File x509CertificateFile, 
  File privateKeyPemFile, 
  final String privateKeyPassword) throws Exception {

  byte[] decryptedByteData = new byte[] {};
  // Get public key certificate
  X509Certificate x509Certificate = CertificateUtils.loadX509CertificateFromFile(x509CertificateFile);

  // The recipient of the S/MIME encrypted message
  RecipientId recipient = new RecipientId();
  recipient.setSerialNumber(x509Certificate.getSerialNumber());
  recipient.setIssuer(x509Certificate.getIssuerX500Principal());

  // The recipient's private key
  FileReader fileReader = new FileReader(privateKeyPemFile);
  PasswordFinder passwordFinder = new PasswordFinder() {
      @Override
      public char[] getPassword() {
          return (privateKeyPassword != null) ? privateKeyPassword.toCharArray() : null;
      }
  };
  PEMReader pemReader = null;
  if (passwordFinder.getPassword() != null && passwordFinder.getPassword().length > 0) {
      pemReader = new PEMReader(fileReader, passwordFinder);
  } else {
      pemReader = new PEMReader(fileReader);
  }
  KeyPair keyPair = (KeyPair) pemReader.readObject();
  PrivateKey privateKey = keyPair.getPrivate();

  try {
      MimeBodyPart encryptedMimeBodyPart = new MimeBodyPart(new ByteArrayInputStream(encryptedByteData));
      SMIMEEnveloped enveloped = new SMIMEEnveloped(encryptedMimeBodyPart);

      // look for our recipient identifier
      RecipientId recipientId = new RecipientId();

      recipientId.setSerialNumber(x509Certificate.getSerialNumber());
      recipientId.setIssuer(x509Certificate.getIssuerX500Principal());

      RecipientInformationStore recipients = enveloped.getRecipientInfos();
      RecipientInformation recipientInfo = recipients.get(recipientId);

      if (recipientInfo != null) {
          decryptedByteData = recipientInfo.getContent(privateKey, BouncyCastleProvider.PROVIDER_NAME);
      }
  } catch (Exception e) {
      throw new EncryptionException("There was an IO problem during the en- or decryption process. See the stacktrace for details.", e);
  } 

  decryptedByteData = Base64.decode(decryptedByteData);
  return decryptedByteData;
}

Create public and private key

You can create the public key (certificate) and private key files used in the methods with OpenSSL which is part of most Linux distributions. Just enter the following on command line:

openssl req \
  -x509 -nodes -days 365 \
  -newkey rsa:1024 -keyout key.pem -out cert.pem

OpenSSL asks several questions about the certificate and creates two file:

  • cert.pem – public key or certificate
  • key.pem – private key

Use this files as parameters in the encrypt and decrypt methods.

  1. No trackbacks yet.

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: