Encrypting/decrypting with DES/CBC/PKCS5Padding

Look at the other questions for more information about the CBC mode and PKCS5Padding. Essentially, a CBC needs a initialization vector (IV) that is basically the seed for encrypting the first block of plaintext. A byte array is filled up with random bytes. You need the same initialization vector for decrypting. You can transmit or save this IV along with your encrypted message. The secret symmetric encryption/decryption key in our case is “password”.

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
 
public class Main
{
   static IvParameterSpec iv;
 
   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("DES");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
 
      // generate an initialization vector (IV)
      SecureRandom secureRandom = new SecureRandom();
      byte[] ivspec = new byte[cipher.getBlockSize()];
      secureRandom.nextBytes(ivspec);
      iv = new IvParameterSpec(ivspec);
 
      // initialize the cipher with the key and IV
      cipher.init(Cipher.ENCRYPT_MODE, sk, iv);
 
      // 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("DES");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
      cipher.init(Cipher.DECRYPT_MODE, sk, iv);
      byte[] decrypted = cipher.doFinal(toDecrypt);
 
      return new String(decrypted);
   }
}

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

Downloading a secure page (HTTPS) with Java

If you try to get data from an HTTPS-enabled page, you will get a MalformedURLException, as shown in following example:

Main.java:

import java.net.*;
import java.io.*;

public class Main {
   public static void main(String[] args) throws Exception {
      URL url = new URL("https://www.sun.com");
      BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
      String line;

      while ((line = br.readLine()) != null) {
         System.out.println(line);
      }
      br.close();
   }
}

outputs:

C:>java Main
Exception in thread "main" java.net.MalformedURLException: unknown protocol: https
        at java.net.URL.<init>(URL.java:497)
        at java.net.URL.<init>(URL.java:364)
        at java.net.URL.<init>(URL.java:308)
        at Main.main(Main.java, Compiled Code)

This is because Sun has no implementation for the HTTPS protocol in their core libraries. However, they created an reference implementation called Java Secure Socket Extension (JSSE) available as seperate download at http://java.sun.com/products/jsse. Include jcert.jar, jnet.jar and jsse.jar in your classpath and add the following two lines of code to the previous program:

      System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
      Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

Here’s the updated example that works:

import java.security.*;
import java.net.*;
import java.io.*;

public class Main {
   public static void main(String[] args) throws Exception {
      // create a new protocol handler
      System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");

      // protocol handler uses this security provider
      Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
      URL url = new URL("https://www.sun.com");
      BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
      String line;

      while ((line = br.readLine()) != null) {
         System.out.println(line);
      }

      br.close();
   }
}

A lenient DateFormat

If DateFormat is not lenient, the Date supplied has to be a valid one. If it is lenient, you can work with dates that are out of range. Eg. Dec. 40th, 2000 will refer to the date Jan 9th, 2001.

Main.java:

import java.util.*;
import java.text.*;
    
public class Main {
   public static void main(String args[]) {
      try {
         Date date;
 
         DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
         date = df.parse("12/40/00");   
         System.out.println("default:t" + date);
 
         df.setLenient(true);
         date = df.parse("12/40/00");   
         System.out.println("lenient:t" + date);
 
         df.setLenient(false);
         date = df.parse("12/40/00");   
         System.out.println("not lenient:t" + date);
      }
      catch(ParseException e) {
         e.printStackTrace();
      }
   }
}

outputs:

default:        Tue Jan 09 00:00:00 CET 2001
lenient:        Tue Jan 09 00:00:00 CET 2001
java.text.ParseException: Unparseable date: "12/40/00"
        at java.text.DateFormat.parse(DateFormat.java:331)
        at Main.main(Main.java:18)

Getting the number of days between two Dates

You can create two date objects, get the number of milliseconds that have passed since Jan 1, 1970 for each of them, make the difference and divide that back by the number of milliseconds per day (= 3600sec/hr * 24hrs * 1000ms)

Main.java:

import java.util.*;
 
public class Main {
   public static void main(String []args) {
      Calendar date1 = Calendar.getInstance();
      date1.set(2001, 6, 4);
 
      Calendar date2 = Calendar.getInstance();
      date2.set(1972, 12, 20);
 
      long diff = (date1.getTime().getTime() - date2.getTime().getTime()) / (3600*24*1000);
      System.out.println("Difference in time: " + diff);
   }
} 

Setting the default Locale in Java

Use Locale.setDefault.

Main.java:

import java.util.*;
 
public class Main {
   public static void main(String []args) {
      // for default locale 
      Locale locale = Locale.getDefault();
      System.out.println(locale);  
 
      Locale.setDefault(new Locale("nl", "BE")); 
      locale = Locale.getDefault();
      System.out.println(locale);  
   }
}

outputs:

en_US
nl_BE

Accessing the Windows registry through the preferences API

On Windows, the preferences API makes use of a DLL to access program-specific properties in the Windows Registry. The following example uses reflection to access private native methods in the preferences API and allows you to get REG_SZ values from the Windows Registry.

For example, to get the IE start page on my machine, I executed:

C:registrytest> c:jdk1.4binjava Main "HKEY_CURRENT_USER\Softw --
are\Microsoft\Internet Explorer\Main" "start page"

http://www.google.com/

It’s a demonstration and works only with JDK1.4. Use at your own risk.

Main.java:

import java.lang.reflect.*;
import java.util.prefs.*;
import java.util.*;
import java.io.*;
 
public class Main
{
   /* Windows security masks */
   private final static int KEY_QUERY_VALUE = 1;
 
   /* Constants used to interpret returns of native functions    */
   private final static int NATIVE_HANDLE = 0;
   private final static int ERROR_CODE = 1;
 
   /*  Windows error codes. */
   private final static int ERROR_SUCCESS = 0;
 
   public static void main(String[] args) {
      if (args.length != 2) {
         System.out.println("Usage: java Main path key");
         System.out.print("  eg.: java Main "HKEY_CURRENT_USER\");
         System.out.print("\Software\\Microsoft\\Internet Explorer\\Main"");
         System.out.println(" "start page"");
         System.exit(1);
      }
 
      try {
         int hkey = getHKEY(args[0]);
         byte[] WINDOWS_ROOT_PATH = stripHKEY(args[0]);
         String key = args[1];
         System.out.println(getValue(hkey, WINDOWS_ROOT_PATH, key));
      }
      catch(Exception e) {
         System.out.println(e.getMessage());
      }
   }
 
   public static int getHKEY(String path) throws Exception {
      if (path.startsWith("HKEY_CURRENT_USER")) {
         return 0x80000001;
      }
      else if (path.startsWith("HKEY_LOCAL_MACHINE")) {
         return 0x80000002;
      }
      else {
         throw new Exception("Path should start with HKEY_CURRENT_USER " + 
                                                 "or HKEY_LOCAL_MACHINE");
      }
   }
 
   public static byte[] stripHKEY(String path) {
      int beginIndex = path.indexOf("\\");
      return stringToByteArray(path.substring(beginIndex+2));
   }
 
   public static String getValue(int hkey, byte[] WINDOWS_ROOT_PATH, String key) 
                                             throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
 
      int[] result = openKey1(hkey, windowsAbsolutePath(WINDOWS_ROOT_PATH),
                              KEY_QUERY_VALUE);
      if (result[ERROR_CODE] != ERROR_SUCCESS) {
         throw new Exception("Path not found!");
      }
      int nativeHandle = result[NATIVE_HANDLE];
 
      Method m = theClass.getDeclaredMethod("WindowsRegQueryValueEx",
                                            new Class[]{int.class, byte[].class});
      m.setAccessible(true);
      byte[] windowsName = toWindowsName(key);
      Object value = m.invoke(null, new Object[]{new Integer(nativeHandle), windowsName});
      WindowsRegCloseKey(nativeHandle);
      if (value == null) {
         throw new Exception("Path found.  Key not found.");
      }
 
      byte[] origBuffer = (byte[]) value;
      byte[] destBuffer = new byte[origBuffer.length - 1];
      System.arraycopy(origBuffer, 0, destBuffer, 0, origBuffer.length - 1);
 
      return new String(destBuffer);
   }
 
   public static int WindowsRegCloseKey(int nativeHandle) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("WindowsRegCloseKey", new Class[]{int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{new Integer(nativeHandle)});
      return ((Integer) ret).intValue();
   }
 
   public static int openKey(byte[] windowsAbsolutePath, int securityMask) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("openKey", new Class[]{byte[].class, int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{windowsAbsolutePath, new Integer(securityMask)});
      return ((Integer) ret).intValue();
   }
 
   public static int[] openKey1(int hkey, byte[] windowsAbsolutePath, int securityMask) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("WindowsRegOpenKey", new Class[]{int.class, 
                                                                             byte[].class, 
                                                                             int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{new Integer(hkey), 
                                               windowsAbsolutePath, 
                                               new Integer(securityMask)});
      return (int[]) ret;
   }
 
   private static byte[] stringToByteArray(String str) {
      byte[] result = new byte[str.length() + 1];
      for (int i = 0; i < str.length(); i++) {
         result[i] = (byte) str.charAt(i);
      }
      result[str.length()] = 0;
      return result;
   } 
 
   private static byte[] windowsAbsolutePath(byte[] WINDOWS_ROOT_PATH) {
      ByteArrayOutputStream bstream = new ByteArrayOutputStream();
      bstream.write(WINDOWS_ROOT_PATH, 0, WINDOWS_ROOT_PATH.length - 1);
      StringTokenizer tokenizer = new StringTokenizer(absolutePath(), "/");
      while (tokenizer.hasMoreTokens()) {
         bstream.write((byte) '\');
         String nextName = tokenizer.nextToken();
         byte[] windowsNextName = toWindowsName(nextName);
         bstream.write(windowsNextName, 0, windowsNextName.length - 1);
      }
      bstream.write(0);
      return bstream.toByteArray();
   }
 
   private static String absolutePath() {
      return "/";
   }
 
   private static byte[] toWindowsName(String javaName) {
      StringBuffer windowsName = new StringBuffer();
      for (int i = 0; i < javaName.length(); i++) {
         char ch = javaName.charAt(i);
         if ((ch < 0x0020) || (ch > 0x007f)) {
            throw new RuntimeException("Unable to convert to Windows name");
         }
         if (ch == '\') {
            windowsName.append("//");
         } else if (ch == '/') {
            windowsName.append('\');
         } else if ((ch >= 'A') && (ch <= 'Z')) {
            windowsName.append("/" + ch);
         } else {
            windowsName.append(ch);
         }
      }
      return stringToByteArray(windowsName.toString());
   }
 
   private static String toJavaValueString(byte[] windowsNameArray) {
      // Use modified native2ascii algorithm
      String windowsName = byteArrayToString(windowsNameArray);
      StringBuffer javaName = new StringBuffer();
      char ch;
      for (int i = 0; i < windowsName.length(); i++) {
         if ((ch = windowsName.charAt(i)) == '/') {
            char next = ' ';
 
            if (windowsName.length() > i + 1 &&
                  (next = windowsName.charAt(i + 1)) == 'u') {
               if (windowsName.length() < i + 6) {
                  break;
               } else {
                  ch = (char) Integer.parseInt
                        (windowsName.substring(i + 2, i + 6), 16);
                  i += 5;
               }
            } else
                  if ((windowsName.length() > i + 1) &&
                  ((windowsName.charAt(i + 1)) >= 'A') && (next <= 'Z')) {
               ch = next;
               i++;
            } else if ((windowsName.length() > i + 1) &&
                  (next == '/')) {
               ch = '\';
               i++;
            }
         } else if (ch == '\') {
            ch = '/';
         }
         javaName.append(ch);
      }
      return javaName.toString();
   }
 
   private static String byteArrayToString(byte[] array) {
      StringBuffer result = new StringBuffer();
      for (int i = 0; i < array.length - 1; i++) {
         result.append((char) array[i]);
      }
      return result.toString();
   }
}

Tokenizing text with a StreamTokenizer

Instantiate a StreamTokenizer, pass it a Reader instance and loop through the available tokens with nextToken. This method returns an integer that refers to the type of token that was read. These are the possibilities:

   TT_EOF		end of file
   TT_EOL		end of line
   TT_NUMBER	numeric value, the actual value is stored in nval
   TT_WORD		word value, the actual value is stored in sval
   "			a quoted string, the actual value is stored in sval
   x			a character token, x replaced by the character converted to an int

This simple example shows you how to read in a text file and print out its tokens.

Main.java:

import java.io.*;
 
public class Main
{
   public static void main(String []args) throws Exception{
      if (args.length != 1) {
         System.out.println("Usage: java Main <file>");
         System.exit(1);
      }
 
      BufferedReader br = new BufferedReader(new FileReader(args[0]));
      StreamTokenizer st = new StreamTokenizer(br);
 
      int t = st.nextToken();
      while (t != StreamTokenizer.TT_EOF) {
         switch(t) {
            case StreamTokenizer.TT_EOL:
               System.out.println("TT_EOL");
               break;
            case StreamTokenizer.TT_NUMBER:
               System.out.println("TT_NUMBER: " + st.nval);
               break;
            case StreamTokenizer.TT_WORD:
               System.out.println("TT_WORD: " + st.sval);
               break;
            case '"':
               System.out.println("quoted string: " + st.sval);
               break;
            default:
               System.out.println("tokentype: " + (char) t);
         }
  
         t = st.nextToken();
      }
   }
}

If we run it on the following text file:

/* 
 * simple program in Java
 */
 
public class Main {
   public static void Main(String []args) {
      // make calculation
      int a = 4 / 2;
 
      System.out.println("result: " + a);
   }
}

it produces the following result.

tokentype: *
TT_WORD: simple
TT_WORD: program
TT_WORD: in
TT_WORD: Java
tokentype: *
TT_WORD: public
TT_WORD: class
TT_WORD: Main
tokentype: {
TT_WORD: public
TT_WORD: static
TT_WORD: void
TT_WORD: Main
tokentype: (
TT_WORD: String
tokentype: [
tokentype: ]
TT_WORD: args
tokentype: )
tokentype: {
TT_WORD: int
TT_WORD: a
tokentype: =
TT_NUMBER: 4.0
TT_WORD: System.out.println
tokentype: (
quoted string: result: 
tokentype: +
TT_WORD: a
tokentype: )
tokentype: ;
tokentype: }
tokentype: }

Notice that /* , / , // and whitespace seem to be left out! In addition, anything that comes after a / is left out too! The reason for this is that StreamTokenizer has a initial setup:

   - 'A' to 'Z' and 'a' to 'z' and u00A0 till u00FF
	are considered wordchars
   - u0000 till u0020 is considered whitespace
   - / is a comment character
   - ' and " are considered quote characters
   - Numbers are parsed (notice 4 has become 4.0)
   - EOL is considered whitespace
   - C/C++ comments are not recognized.

You can customize the StreamTokenizer in a number of ways:

1. wordChars(int lo, int hi)

The lo and hi parameters specify the unicode range of characters that you would like to see treated as part of a word. You can call this method several times to include several ranges. Try this after you have instantiated the StreamTokenizer:

      // consider all values in the range '{' and '}' as whitespace
      st.wordChars('{', '}');

2. whitespaceChars(int lo, int hi)

The lo and hi parameters specify the unicode range of characters that you would like to see treated as whitespace. You can call this method several times to include several ranges. Try this:

      // consider all values in the range '{' and '}' as whitespace
      st.whitespaceChars('{', '}'); 

3. ordinaryChars(int lo, int hi)

The lo and hi parameters specify the unicode range of characters that you would like to see treated as being an ordinary character, meaning it’s not part of a word, number, whitespace, etc. It will be returned by nextToken as a single character. There’s a variation on this method that takes only one parameter. Try this:

      // consider all values in the range 'a' to 'g' as ordinary char
      st.ordinaryChars('a', 'g');

4. commentChar(int ch)

Specifies that the value ch should be treated as a comment character, meaning the character plus the rest of the line is ignored. Try this:

      // treat 'p' as being a comment
      st.commentChar('p');

5. quoteChar(int ch)

Tells the tokenizer that all characters between this delimiter ch are treated as a string constant. Try this:

      st.quoteChar('/');

6. parseNumbers

This tells the tokenizer that characters from 0 to 9, the period and the minus sign should be recognized as being part of a TT_NUMBER token, if it can be constructed. By default, parseNumbers is set. You can have . and – treated otherwise but then you would have to use the methods ordinaryChar or wordChars.

7. eolIsSignificant(boolean b)

If b is set, TT_EOL will be returned whenever an end-of-line is encountered. Otherwise, they are ignored. Try this:

      st.eolIsSignificant(true);

8. slashStarComments(boolean b)

If b is set, all characters between /* and */ are ignored (C style comments)

9. slashSlashComments(boolean b)

If b is set, // is recognized as being comments (the rest of the line is ignored). (C++ style comments)

10. lowerCaseMode(boolean lc)

if lc is set, all word tokens are lowercased when returned.

11. pushBack()

“Pushes” the last token that was returned back on the stream. Next time nextToken is invoked, the same token will be returned as the last one.

Then there’s another member variable lineno that you may invoke at any time to get the current linenumber.

Using the BorderFactory in Swing

If you have lots of components with borders in your Swing GUI, you could create a Border instance for every component. The BorderFactory class provides a way to share border instances among different components. When using the class for the first time, it creates a number of static borders that it reuses and returns when you call one of the static create methods that the class exposes.

Main.java:

import javax.swing.border.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   public Main() {
      getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT));
 
      JLabel label1 = new JLabel("Label 1");
      label1.setBorder(BorderFactory.createLoweredBevelBorder()); 
 
      // reuse border
      JLabel label2 = new JLabel("Label 2");
      label2.setBorder(BorderFactory.createLoweredBevelBorder()); 
 
      getContentPane().add(label1);
      getContentPane().add(label2);
      
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String [] args) {
      Main main = new Main();
      main.pack();
      main.setVisible(true);
   } 
} 

Maximizing a JFrame

This is as close as you can get: just resize the window to the current screensize:

 
import javax.swing.*;
import java.awt.*;
   
public class Maximize extends JFrame {
 
   public Maximize() {
      Toolkit tk = getToolkit();
      
      setSize((int) getToolkit().getScreenSize().getWidth(), 
              (int) getToolkit().getScreenSize().getHeight());
   }
 
   public static void main(String args[]) {
      new Maximize().setVisible(true);     
   }
}

Scrolling a JScrollPane to the bottom programmatically

Call the method scrollRectToVisible of the component that is added to the JScrollPane container as shown in following example:

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   public Main() throws Exception {
      getContentPane().setLayout(new BorderLayout());
 
      final JPanel panel = createPanel(); 
      final JScrollPane scrollpane = new JScrollPane(panel);
 
      JButton button = new JButton("Scroll to bottom!");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            panel.scrollRectToVisible(
              new Rectangle(0, panel.getHeight()-1, 1, 1));
         }
      });
 
      getContentPane().add(BorderLayout.NORTH, button);
      getContentPane().add(BorderLayout.CENTER, scrollpane);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   }
 
   public static JPanel createPanel() throws Exception {
      JPanel panel = new JPanel();
      panel.setLayout(new GridLayout(50, 20, 10, 10));
 
      for (int i=0; i<50; i++) {
         for (int j=0; j<20; j++) {
            JLabel label = new JLabel("label " + i + ", " + j);
            panel.add(label);    
         }
      }
 
      return panel;
   }
 
   public static void main(String [] args) throws Exception  {
      Main main = new Main();
      main.setSize(600, 600);
      main.setVisible(true);
   } 
}