001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.util;
017:
018: import java.io.UnsupportedEncodingException;
019: import java.security.spec.KeySpec;
020:
021: import javax.crypto.Cipher;
022: import javax.crypto.SecretKey;
023: import javax.crypto.SecretKeyFactory;
024: import javax.crypto.spec.DESedeKeySpec;
025:
026: import org.acegisecurity.AcegiSecurityException;
027: import org.apache.commons.codec.binary.Base64;
028: import org.springframework.util.Assert;
029:
030: /**
031: * A static utility class that can encrypt and decrypt text.
032: *
033: * <p>This class is useful if you have simple needs and wish to use the DESede
034: * encryption cipher. More sophisticated requirements will need to use the
035: * Java crypto libraries directly.
036: *
037: * @author Alan Stewart
038: * @author Ben Alex
039: * @version $Id: EncryptionUtils.java 1784 2007-02-24 21:00:24Z luke_t $
040: */
041: public final class EncryptionUtils {
042:
043: /**
044: * This is a static class that should not be instantiated.
045: */
046: private EncryptionUtils() {
047: }
048:
049: /**
050: * Converts a String into a byte array using UTF-8, falling back to the
051: * platform's default character set if UTF-8 fails.
052: *
053: * @param input the input (required)
054: * @return a byte array representation of the input string
055: */
056: public static byte[] stringToByteArray(String input) {
057: Assert.hasLength(input, "Input required");
058: try {
059: return input.getBytes("UTF-8");
060: } catch (UnsupportedEncodingException fallbackToDefault) {
061: return input.getBytes();
062: }
063: }
064:
065: /**
066: * Converts a byte array into a String using UTF-8, falling back to the
067: * platform's default character set if UTF-8 fails.
068: *
069: * @param byteArray the byte array to convert (required)
070: * @return a string representation of the byte array
071: */
072: public static String byteArrayToString(byte[] byteArray) {
073: Assert.notNull(byteArray, "ByteArray required");
074: Assert
075: .isTrue(byteArray.length > 0,
076: "ByteArray cannot be empty");
077: try {
078: return new String(byteArray, "UTF8");
079: } catch (final UnsupportedEncodingException e) {
080: return new String(byteArray);
081: }
082: }
083:
084: private static byte[] cipher(String key, byte[] passedBytes,
085: int cipherMode) throws EncryptionException {
086: try {
087: final KeySpec keySpec = new DESedeKeySpec(
088: stringToByteArray(key));
089: final SecretKeyFactory keyFactory = SecretKeyFactory
090: .getInstance("DESede");
091: final Cipher cipher = Cipher
092: .getInstance("DESede/ECB/PKCS5Padding");
093: final SecretKey secretKey = keyFactory
094: .generateSecret(keySpec);
095: cipher.init(cipherMode, secretKey);
096: return cipher.doFinal(passedBytes);
097: } catch (final Exception e) {
098: throw new EncryptionException(e.getMessage(), e);
099: }
100: }
101:
102: /**
103: * Encrypts the inputString using the key.
104: *
105: * @param key at least 24 character long key (required)
106: * @param inputString the string to encrypt (required)
107: * @return the encrypted version of the inputString
108: * @throws EncryptionException in the event of an encryption failure
109: */
110: public static String encrypt(String key, String inputString)
111: throws EncryptionException {
112: isValidKey(key);
113: final byte[] cipherText = cipher(key,
114: stringToByteArray(inputString), Cipher.ENCRYPT_MODE);
115: return byteArrayToString(Base64.encodeBase64(cipherText));
116: }
117:
118: /**
119: * Encrypts the inputBytes using the key.
120: *
121: * @param key at least 24 character long key (required)
122: * @param inputBytes the bytes to encrypt (required)
123: * @return the encrypted version of the inputBytes
124: * @throws EncryptionException in the event of an encryption failure
125: */
126: public static byte[] encrypt(String key, byte[] inputBytes)
127: throws EncryptionException {
128: isValidKey(key);
129: return Base64.encodeBase64(cipher(key, inputBytes,
130: Cipher.ENCRYPT_MODE));
131: }
132:
133: /**
134: * Decrypts the inputString using the key.
135: *
136: * @param key the key used to originally encrypt the string (required)
137: * @param inputString the encrypted string (required)
138: * @return the decrypted version of inputString
139: * @throws EncryptionException in the event of an encryption failure
140: */
141: public static String decrypt(String key, String inputString)
142: throws EncryptionException {
143: Assert.hasText(key, "A key is required to attempt decryption");
144: final byte[] cipherText = cipher(key, Base64
145: .decodeBase64(stringToByteArray(inputString)),
146: Cipher.DECRYPT_MODE);
147: return byteArrayToString(cipherText);
148: }
149:
150: /**
151: * Decrypts the inputBytes using the key.
152: *
153: * @param key the key used to originally encrypt the string (required)
154: * @param inputBytes the encrypted bytes (required)
155: * @return the decrypted version of inputBytes
156: * @throws EncryptionException in the event of an encryption failure
157: */
158: public static byte[] decrypt(String key, byte[] inputBytes)
159: throws EncryptionException {
160: Assert.hasText(key, "A key is required to attempt decryption");
161: return cipher(key, Base64.decodeBase64(inputBytes),
162: Cipher.DECRYPT_MODE);
163: }
164:
165: private static void isValidKey(String key) {
166: Assert.hasText(key,
167: "A key to perform the encryption is required");
168: Assert.isTrue(key.length() >= 24,
169: "Key must be at least 24 characters long");
170: }
171:
172: public static class EncryptionException extends
173: AcegiSecurityException {
174: private static final long serialVersionUID = 1L;
175:
176: public EncryptionException(String message, Throwable t) {
177: super (message, t);
178: }
179:
180: public EncryptionException(String message) {
181: super(message);
182: }
183: }
184: }
|