KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > runtime > Cipher


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.runtime;
12
13 import java.io.UnsupportedEncodingException JavaDoc;
14 import java.security.MessageDigest JavaDoc;
15 import java.util.Random JavaDoc;
16
17 /**
18  * <P>Encrypts or decrypts a sequence of bytes. The bytes are decrypted
19  * by supplying the same password that was given when the bytes were
20  * encrypted.
21  * <P>Here is an example showing how to encrypt and then decrypt the
22  * string "Hello, world!" using the password "music":
23  * <pre>
24  * String password = "music";
25  * byte[] data = "Hello, world!".getBytes("UTF8");
26  *
27  * // Encrypt
28  * Cipher cipher = new Cipher(ENCRYPT_MODE, password);
29  * byte[] encrypted = cipher.cipher(data);
30  *
31  * // Decrypt
32  * cipher = new Cipher(DECRYPT_MODE, password);
33  * byte[] decrypted = cipher.cipher(encrypted);
34  * </pre>
35  */

36 public class Cipher {
37     public static final int DECRYPT_MODE = -1;
38     public static final int ENCRYPT_MODE = 1;
39     private static final int RANDOM_SIZE = 16;
40
41     private int mode = 0;
42     private byte[] password = null;
43
44     //the following fields are used for generating a secure byte stream
45
//used by the decryption algorithm
46
private byte[] byteStream;
47     private int byteStreamOffset;
48     private MessageDigest JavaDoc digest;
49     private Random JavaDoc random;
50     private final byte[] toDigest;
51
52     /**
53      * Initializes the cipher with the given mode and password. This method
54      * must be called first (before any encryption of decryption takes
55      * place) to specify whether the cipher should be in encrypt or decrypt
56      * mode and to set the password.
57      *
58      * @param mode
59      * @param passwordString
60      */

61     public Cipher(int mode, String JavaDoc passwordString) {
62         this.mode = mode;
63         try {
64             this.password = passwordString.getBytes("UTF8"); //$NON-NLS-1$
65
} catch (UnsupportedEncodingException JavaDoc e) {
66             this.password = passwordString.getBytes();
67         }
68         toDigest = new byte[password.length + RANDOM_SIZE];
69     }
70
71     /**
72      * Encrypts or decrypts (depending on which mode the cipher is in) the
73      * given data and returns the result.
74      *
75      * @param data
76      * @return the result of encrypting or decrypting the given data
77      */

78     public byte[] cipher(byte[] data) throws Exception JavaDoc {
79         return transform(data, 0, data.length, mode);
80     }
81
82     /**
83      * Encrypts or decrypts (depending on which mode the cipher is in) the
84      * given data and returns the result.
85      *
86      * @param data the byte array containg the given data
87      * @param off the index of the first byte in the given byte array
88      * to be transformed
89      * @param len the number of bytes to be transformed
90      * @return the result of encrypting or decrypting the given data
91      */

92     public byte[] cipher(byte[] data, int off, int len) throws Exception JavaDoc {
93         return transform(data, off, len, mode);
94     }
95
96     /**
97      * Encrypts or decrypts (depending on which mode the cipher is in) the
98      * given byte and returns the result.
99      *
100      * @param datum the given byte
101      * @return the result of encrypting or decrypting the given byte
102      */

103     public byte cipher(byte datum) throws Exception JavaDoc {
104         byte[] data = {datum};
105         return cipher(data)[0];
106     }
107
108     /**
109      * Generates a secure stream of bytes based on the input seed.
110      * This routine works by combining the input seed with random bytes
111      * generated by a random number generator, and then computing the
112      * SHA-1 hash of those bytes.
113      */

114     private byte[] generateBytes() throws Exception JavaDoc {
115         if (digest == null) {
116             digest = MessageDigest.getInstance("SHA"); //$NON-NLS-1$
117
//also seed random number generator based on password
118
long seed = 0;
119             for (int i = 0; i < password.length; i++)
120                 //this function is known to give good hash distribution for character data
121
seed = (seed * 37) + password[i];
122             random = new Random JavaDoc(seed);
123         }
124         //add random bytes to digest array
125
random.nextBytes(toDigest);
126
127         //overlay password onto digest array
128
System.arraycopy(password, 0, toDigest, 0, password.length);
129
130         //compute and return SHA-1 hash of digest array
131
return digest.digest(toDigest);
132     }
133
134     /**
135      * Returns a stream of cryptographically secure bytes of the given length.
136      * The result is deterministically based on the input seed (password).
137      */

138     private byte[] nextRandom(int length) throws Exception JavaDoc {
139         byte[] nextRandom = new byte[length];
140         int nextRandomOffset = 0;
141         while (nextRandomOffset < length) {
142             if (byteStream == null || byteStreamOffset >= byteStream.length) {
143                 byteStream = generateBytes();
144                 byteStreamOffset = 0;
145             }
146             nextRandom[nextRandomOffset++] = byteStream[byteStreamOffset++];
147         }
148         return nextRandom;
149     }
150
151     private byte[] transform(byte[] data, int off, int len, int mod) throws Exception JavaDoc {
152         byte[] result = nextRandom(len);
153         for (int i = 0; i < len; ++i) {
154             result[i] = (byte) (data[i + off] + mod * result[i]);
155         }
156         return result;
157     }
158 }
159
Popular Tags