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)

What is a message digest?

A messagedigest is a sortof a fingerprint for a chunk of data. If only one bit of that data has changed, the message digest algorithm would generate a different fingerprint. This allows you to determine if, for example during network transmission of data, that data has changed. You cannot deduce the original contents of a message from a message digest.

A common example is the use of a password system, where passwords are stored as messagedigests. When you logon to the system, it will compute a messagedigest of the password you’ve typed in and compare it with the messagedigest that is stored in the username/password file.

There are two popular types of message digest algorithms: MD5 and SHA.

For example, the MD5 message digest for the plaintext The sun is green and the grass shines is (in hex) 470DB3B23F9D445446DFCE291C9F17AB.

For information on how to generate a messagedigest in Java, look at this answer.

Encrypting/decrypting using Skipjack

Check out the following pages for more infomration on Skipjack encryption:
http://www.tropsoft.com/strongenc/skipjack.htm
http://www.cs.technion.ac.il/~biham/Reports/SkipJack/note1.html

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("Skipjack");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance("Skipjack");
 
      // 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("Skipjack");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance("Skipjack");
      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)

Generating a MD5 message digest

What MD5 is and why it it important is explained well on the following page:

http://www.enteract.com/~lspitz/md5.html

A digest has two properties:
- it is computationally infeasible to find another input string that generates the same digest
- the digest does not reveal anything about the input that was used to generate it.

The engine class MessageDigest provides the functionality of several
types of cryptographic algorithms. What algorithms are available depends
on the provider you are using. For example, Sun (the default provider) supplies
implementations of the MD5 and SHA-1 message digest algorithms. Other providers
may have their own implementation of these algorithms or other algorithms.

As an implementation is supplied by Sun in the JDK, you don’t even have to
install another provider. Here’s is an example using the implementation by Cryptix:

 
import cryptix.util.core.Hex;
import cryptix.util.test.BaseTest;
import java.security.MessageDigest;
 
class TestMD5 
{
   public static void main(String[] args) {
      String plaintext = "The sun is green and the grass shines";

      MessageDigest md = null;
      try {
         // first create an instance, given the provider
         md = MessageDigest.getInstance("MD5", "Cryptix");
      }
      catch(java.security.NoSuchProviderException e) {
         System.out.println(e);
         System.exit(1);
      }
      catch(java.security.NoSuchAlgorithmException e) {
         System.out.println(e);
         System.exit(1);
      }

      md.reset();

      // call the update method one or more times 
      // (useful when you don't know the size of your data, eg. stream)
      md.update(plaintext.getBytes());

      // now calculate the hash
      byte[] hash = md.digest();

      System.out.println("Plaintext:nt" + plaintext + "n");
      // Hex is a function provided by Cryptix to produce a nice output
      System.out.println("Message Digest:nt" + Hex.toString(hash));
   }
}

generates the output:

 
Plaintext:
	The sun is green and the grass shines

Message Digest:
	470DB3B23F9D445446DFCE291C9F17AB

What is asymmetric cryptography?

The problem with symmetric cryptography is how to distribute the secret key to the involved parties. In assymetric cryptography (also: public key cryptography), algorithms use two different keys: a private and a public one. A message encrypted with a private key can be decrypted with its public key (and in some cases vice versa). The owner of the key pair holds the private key, and may distribute the public key to anyone. Someone who wants to send a secret message uses the public key of the intended receiver to encrypt it. Only the receiver holds the private key and can decrypt it.

Compared to secret key encryption, public key encryption is slow.

A popular assymetric cryptographic algorithm is RSA, used in PGP.