Install the free Bouncy Castle JCE Provider

Bouncy Castle is a free provider for JCE. These following steps will explain how to add this security provider.

  1. Download the latest release for your JDK version at http://www.bouncycastle.org/latest_releases.html
  2. Extract the zip file in your home directory
  3. BouncyCastle doens’t come with a JAR file. In order to add it to the bootclasspath, create one:
         c:jce-jdk12-107classes> jar cvf bouncycastle.jar *
         c:jce-jdk12-107classes> copy bouncycastle.jar c:jdk1.2.2jrelibext
    
  4. Go to your JAVA_HOME/jre/lib/security directory and edit the file java.security. Look at the configuration, in my case it says something like:
       security.provider.1=sun.security.provider.Sun
       security.provider.2=com.sun.crypto.provider.SunJCE
    

    Add the line security.provider.3=org.bouncycastle.jce.provider.BouncyCastleProvider

  5. Run one of the examples to see if it is working (eg. How do I crypt/decrypt a message with the Blowfish algorithm?)

Update:

This information is outdated. Now, you can download JAR versions for your JDK version.

For 1.3.1, I downloaded jce-jdk13-118.jar and bcprov-jdk13-118.jar and added them to my classpath (you can also put them in jdk1.3.1/jre/lib/ext and NOT add them to your classpath).

You can add a static provider to jdk1.3.1/jre/lib/security/java.security as described above or you can do this programmatically in your code:

...
   java.security.Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
   Security.addProvider(provider);

Encrypting/decrypting using RC4

RC4 (Ron’s Code) is a symmetric key encryption algorithm. Developed in 1987 by Ronald Rivest, it is used in SSL and many applications such as Lotus Notes and Oracle Secure SQL.

RC4 is a stream cipher, meaning that it encrypts one byte at a time. With RC4, the key is variable, from 1 to 2048 bits. RC4 is about 10 times as fast as DES. The algorithm is small and simple to implement. Here’s an unreadable version of it written in Perl.

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
 
public class Main
{
   private static String algorithm = "RC4";
 
   public static void main(String []args) throws Exception {
      String toEncrypt = "The shorter you live, the longer you're dead!";
 
      System.out.println("Encrypting...");
      byte[] encrypted = encrypt(toEncrypt, "password");
 
      System.out.println("Decrypting...");
      String decrypted = decrypt(encrypted, "password");
    
      System.out.println("Decrypted text: " + decrypted);
   } 
 
   public static byte[] encrypt(String toEncrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance(algorithm);
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance(algorithm);
 
      // initialize the cipher with the key
      cipher.init(Cipher.ENCRYPT_MODE, sk);
 
      // enctypt!
      byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
 
      return encrypted;
   }
 
   public static String decrypt(byte[] toDecrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance(algorithm);
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance(algorithm);
      cipher.init(Cipher.DECRYPT_MODE, sk);
      byte[] decrypted = cipher.doFinal(toDecrypt);
 
      return new String(decrypted);
   }
}

Getting the current NT/2000/XP user using JAAS

Note: if you are using a JDK less than 1.4, make sure you have downloaded the JAAS class libraries and the sample authentication module for Windows at http://java.sun.com/products/jaas/index-10.html. Put jaas.jar and jaasmod.jar in your classpath.

Main.java:

import com.sun.security.auth.module.NTSystem;
 
public class Main {
   public static void main(String []args) {
      NTSystem ntSystem = new NTSystem();
      System.out.println(ntSystem.getName());
   }
}

outputs on my machine:

C:myjaastest>java -Djava.library.path=c:javatoolsjaasmod1_0lib Main
esus

To get other NT properties:

import com.sun.security.auth.module.NTSystem;
import java.util.Arrays;

public class Main {
   public static void main(String []args) {
      NTSystem ntSystem = new NTSystem();
      System.out.println(ntSystem.getName());
      System.out.println(ntSystem.getDomain());
      System.out.println(ntSystem.getDomainSID());
      System.out.println(Arrays.asList((Object[])ntSystem.getGroupIDs()));
      System.out.println(ntSystem.getImpersonationToken());
      System.out.println(ntSystem.getPrimaryGroupID());
      System.out.println(ntSystem.getUserSID());
   }
}

outputs:

C:myjaastest>java -Djava.library.path=c:javatoolsjaasmod1_0lib Main
esus
WORKGROUP

[S-1-5-21-3978503659-2915903831-1203752577-513, S-1-1-0, S
-1-5-32-544, S-1-5-32-545, S-1-5-5-0-51662, S-1-2-0, S-1-5
-4, S-1-5-11]
1252
S-1-5-21-3978503659-2915903831-1203752577-513
S-1-5-21-3978503659-2915903831-1203752577-1007

What is PKCS#5 padding?

Ciphers process data in blocks, for example 8 byte blocks. If the length of the data that you want to encrypt is not evenly divisible by the blocksize that your encryption algorithm uses, the data needs to be padded. PKCS#5 is one way of padding. It appends to every message a block of data varying from 1 to 8 bytes where each bytes contain the number of bytes that are padded.

For instance, if the length of the data is 10, then 6 bytes need to be padded. The last block of 8 bytes will look like this:

 +---+---+---+---+---+---+---+---+
 | D | D | 6 | 6 | 6 | 6 | 6 | 6 |
 +---+---+---+---+---+---+---+---+

If the length of your data happens to be evenly divisible by 8, an extra 8 bytes will be added looking like this:

 +---+---+---+---+---+---+---+---+
 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
 +---+---+---+---+---+---+---+---+

This is because PKCS5Padding always assumes there is a pad.

Encrypting/decrypting using RC5

RC5 (Ron’s Code) is a block cipher, blocks of data are encrypted. Block size, key size and security level can be customized. In his paper, Ronald Rivest talks about a “variable number of rounds” allowing the user to make a tradeoff between higher security and higher speed, and a “variable length cryptographic key”. For more information, consult this cryptobytes edition (PDF).

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
 
public class Main
{
   private static String algorithm = "RC5";
 
   public static void main(String []args) throws Exception {
      String toEncrypt = "The shorter you live, the longer you're dead!";
 
      System.out.println("Encrypting...");
      byte[] encrypted = encrypt(toEncrypt, "password");
 
      System.out.println("Decrypting...");
      String decrypted = decrypt(encrypted, "password");
    
      System.out.println("Decrypted text: " + decrypted);
   } 
 
   public static byte[] encrypt(String toEncrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance(algorithm);
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance(algorithm);
 
      // initialize the cipher with the key
      cipher.init(Cipher.ENCRYPT_MODE, sk);
 
      // enctypt!
      byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
 
      return encrypted;
   }
 
   public static String decrypt(byte[] toDecrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance(algorithm);
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance(algorithm);
      cipher.init(Cipher.DECRYPT_MODE, sk);
      byte[] decrypted = cipher.doFinal(toDecrypt);
 
      return new String(decrypted);
   }
}

Get a private key from a keystore

This example extracts a private key from a keystore and prints it out in PEM format.

Main.java:

import sun.misc.BASE64Encoder;
import java.security.cert.Certificate;
import java.security.*;
import java.io.File;
import java.io.FileInputStream;
 
class Main {
   public static void main(String args[]) throws Exception{
      if (args.length != 3) {
         System.out.println("Extracts private key in PEM format from a JKS keystore");
         System.out.println("Usage: java Main <keystore> <alias> <passphrase>");
         System.exit(1);
      }
 
      String keystore = args[0];
      String alias = args[1];
      String password = args[2];      
 
      KeyStore ks = KeyStore.getInstance("JKS");
      char[] passphrase = password.toCharArray();
      BASE64Encoder base64Encoder = new BASE64Encoder();
 
      ks.load(new FileInputStream(keystore), passphrase);
 
      PrivateKey privateKey = getPrivateKey(ks, alias, passphrase);
 
      String sPrivateKey = base64Encoder.encode(privateKey.getEncoded());
 
      System.out.println("-----BEGIN PRIVATE KEY-----");
      System.out.println(sPrivateKey);
      System.out.println("-----END PRIVATE KEY-----");
   }
 
   public static PrivateKey getPrivateKey(KeyStore keystore, String alias, char[] password) {
      try {
         Key key = keystore.getKey(alias, password);
         if (key instanceof PrivateKey) {
            Certificate cert = keystore.getCertificate(alias);
            PublicKey publicKey = cert.getPublicKey();
 
            KeyPair kp = new KeyPair(publicKey, (PrivateKey)key);
 
            return kp.getPrivate();
         }
      } catch (UnrecoverableKeyException e) {
         e.printStackTrace();
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
      } catch (KeyStoreException e) {
         e.printStackTrace();
      }
 
      return null;
   }
}

What is privileged code?

It allows you to temporarily grant permission to code that would normally not have permission to run. Normally, the entire execution stack (all callers) needs to have permission to do a sensitive operation.

With Privileged Code, you can specify in a fine-grained way that only the final class in the execution stack needs permission.

For example, consider the following two classes.

Main.java:

public class Main
{
   public static void main(String []args) {
      LowLevel.executeLowLevelAction();
   }
}

LowLevel.java:

public class LowLevel
{
   public static void executeLowLevelAction() {
      System.out.println(System.getProperty("test"));
   }
}

The Main class just executes the static method executeLowLevelAction that gets the property
test.
Run log:

C:> java -Dtest="Hello, World!" Main
Hello, World!
 
C:> java -Dtest="Hello, World!" -Djava.security.manager Main
Exception in thread "main" java.security.AccessControlException: access denied
java.util.PropertyPermission test read)
        at java.security.AccessControlContext.checkPermission(AccessControlCont
xt.java:195)
        at java.security.AccessController.checkPermission(AccessController.java
403)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1
43)
        at java.lang.System.getProperty(System.java:539)
        at LowLevel.executeLowLevelAction(LowLevel.java:6)
        at Main.main(Main.java:4)

As you expected, the first run can just get the property test without needing any permissions (as no security manager is installed by default). In the second run, we ask the VM to set up a default SecurityManager which results in an AccessControlException because reading System Property “test” is not allowed.

To grant permission to read this property, we need to write a policy security configuration file. But we really only want the class LowLevel to have permission to read the property. We do not want to grant the calling class Main that permission.

So what we could do is jar the LowLevel class up and write a policy file to grant that jar file additional permissions:

C:> jar cvf LowLevel.jar LowLevel.class
added manifest
adding: LowLevel.class(in = 474) (out= 308)(deflated 35%)

C:> del LowLevel.class

mypolicy:

grant codeBase "file:/c:/LowLevel.jar" {
   Permission java.util.PropertyPermission "test", "read";
};

Run log:

C:> java -Dtest="Hello, World!" -Djava.security.manager 
          -Djava.seurity.policy=mypolicy Main
 
Exception in thread "main" java.security.AccessControlException: access denied
java.util.PropertyPermission test read)
        at java.security.AccessControlContext.checkPermission(AccessControlCont
xt.java:195)
        at java.security.AccessController.checkPermission(AccessController.java
403)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1
43)
        at java.lang.System.getProperty(System.java:539)
        at LowLevel.executeLowLevelAction(LowLevel.java:6)
        at Main.main(Main.java:4)

AccessControlException!!? How come? Didn’t we grant the permission to LowLevel.jar to read the property “test”? The problem lays in the requirement that every class in the execution stack must have the permission.

The solution is to make the System.getProperty call in a Privileged Block. This could be done as follows.

LowLevel.java:

import java.security.*;
 
public class LowLevel
{
   public static void executeLowLevelAction() {
      String testprop = (String) AccessController.doPrivileged(new PrivilegedAction() {
         public Object run() {
            return System.getProperty("test");
         }
      });
      System.out.println(testprop);
   }
}

Compile and jar it up:

C:> javac LowLevel.java

C:> jar cvf LowLevel.jar LowLevel.class LowLevel$1.class
added manifest
adding: LowLevel.class(in = 603) (out= 384)(deflated 36%)
adding: LowLevel$1.class(in = 449) (out= 307)(deflated 31%)
 
C:> del LowLevel*.class

and run it again:

C:> java -Dtest="Hello, World!" -Djava.security.manager -Djava.sec
urity.policy=mypolicy Main
Hello, World!

Now we get the correct response: allowing only the class LowLevel to run “sensitive” code, no matter who called it, so without worrying about the executing stack.

Difference between the methods update() and doFinal() in Cipher

update() adds data to the Cipher’s internal buffer, then returns all currently completely encoded blocks. If there are any encoded blocks left over, they remain in the Cipher’s buffer until the next call, or a call to doFinal(). This means that if you call update() with a four byte array to encrypt, and the buffer size is eight bytes, you will not receive encoded data on the return (you’ll get a null instead). If your next call to update() passes five bytes of data in, you will get an 8 byte (the block size) array back, containing the four bytes passed in on the previous call, the first four bytes from the current call – the remaining byte from the current call is left in the Cipher’s buffer.

doFinal() on the other hand is much simpler: it encrypts the passed data, pads it out to the necessary length, and then returns it. The Cipher is essentially stateless.

Encrypting/decrypting using Rijndael (AES)

Rijndael has been selected as the proposed AES algorithm (check out http://csrc.nist.gov/encryption/aes/aesfact.html. You can find more information of Rijdael on the homepage of the designer(s).

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
import org.bouncycastle.util.encoders.Hex;
 
public class Main
{
   public static void main(String []args) throws Exception {
      String toEncrypt = "The shorter you live, the longer you're dead!";
 
      System.out.println("Encrypting...");
      byte[] encrypted = encrypt(toEncrypt, "password");
 
      System.out.println("Decrypting...");
      String decrypted = decrypt(encrypted, "password");
    
      System.out.println("Decrypted text: " + decrypted);
   } 
 
   public static byte[] encrypt(String toEncrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance("Rijndael");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance("Rijndael");
 
      // initialize the cipher with the key
      cipher.init(Cipher.ENCRYPT_MODE, sk);
 
      // enctypt!
      byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
 
      return encrypted;
   }
 
   public static String decrypt(byte[] toDecrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance("Rijndael");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance("Rijndael");
      cipher.init(Cipher.DECRYPT_MODE, sk);
      byte[] decrypted = cipher.doFinal(toDecrypt);
 
      return new String(decrypted);
   }
}

(tested with the BouncyCastle JCE provider, http://www.bouncycastle.org)