001: /*
002: * $Header: /cvsroot/mvnforum/myvietnam/src/net/myvietnam/mvncore/security/Encoder.java,v 1.26 2008/01/28 09:35:09 minhnn Exp $
003: * $Author: minhnn $
004: * $Revision: 1.26 $
005: * $Date: 2008/01/28 09:35:09 $
006: *
007: * ====================================================================
008: *
009: * Copyright (C) 2002-2007 by MyVietnam.net
010: *
011: * All copyright notices regarding MyVietnam and MyVietnam CoreLib
012: * MUST remain intact in the scripts and source code.
013: *
014: * This library is free software; you can redistribute it and/or
015: * modify it under the terms of the GNU Lesser General Public
016: * License as published by the Free Software Foundation; either
017: * version 2.1 of the License, or (at your option) any later version.
018: *
019: * This library is distributed in the hope that it will be useful,
020: * but WITHOUT ANY WARRANTY; without even the implied warranty of
021: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
022: * Lesser General Public License for more details.
023: *
024: * You should have received a copy of the GNU Lesser General Public
025: * License along with this library; if not, write to the Free Software
026: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
027: *
028: * Correspondence and Marketing Questions can be sent to:
029: * info at MyVietnam net
030: *
031: * @author: Minh Nguyen
032: * @author: Mai Nguyen
033: */
034: package net.myvietnam.mvncore.security;
035:
036: import java.io.UnsupportedEncodingException;
037: import java.net.URLDecoder;
038: import java.net.URLEncoder;
039: import java.security.*;
040:
041: import javax.crypto.*;
042: import javax.crypto.spec.SecretKeySpec;
043:
044: import net.myvietnam.mvncore.misc.Base64;
045: import net.myvietnam.mvncore.util.MailUtil;
046:
047: import org.apache.commons.codec.binary.Hex;
048: import org.apache.commons.logging.Log;
049: import org.apache.commons.logging.LogFactory;
050:
051: public class Encoder {
052:
053: private static Log log = LogFactory.getLog(Encoder.class);
054:
055: // Please note that 2 below methods are used in #getMD5_Base64 only
056: // use them in other methods will make it not thread-safe
057: private static MessageDigest digest = null;
058:
059: private static boolean isInited = false;
060:
061: private Encoder() {
062: }
063:
064: /**
065: * This method return a String that has been encrypted as MD5 and then escaped using Base64.<p>
066: * This method should be used to encrypt all password for maximum security.
067: * @param input String the string that need encrypted
068: * @return String the string after encrypted
069: */
070: public static synchronized String getMD5_Base64(String input) {
071: // please note that we dont use digest, because if we
072: // cannot get digest, then the second time we have to call it
073: // again, which will fail again
074: if (isInited == false) {
075: isInited = true;
076: try {
077: digest = MessageDigest.getInstance("MD5");
078: } catch (Exception ex) {
079: log
080: .fatal(
081: "Cannot get MessageDigest. Application may fail to run correctly.",
082: ex);
083: }
084: }
085: if (digest == null)
086: return input;
087:
088: // now everything is ok, go ahead
089: try {
090: digest.update(input.getBytes("UTF-8"));
091: } catch (java.io.UnsupportedEncodingException ex) {
092: log.error("Assertion: This should never occur.");
093: }
094: byte[] rawData = digest.digest();
095: byte[] encoded = Base64.encode(rawData);
096: String retValue = new String(encoded);
097: return retValue;
098: }
099:
100: public static String encrypt_AES_to_HEX(String input, String key)
101: throws NoSuchAlgorithmException, NoSuchPaddingException,
102: InvalidKeyException, IllegalBlockSizeException,
103: BadPaddingException {
104:
105: byte[] desKeyData = key.getBytes();
106:
107: SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "AES");
108:
109: Cipher c = Cipher.getInstance("AES");
110:
111: c.init(Cipher.ENCRYPT_MODE, secretKey);
112:
113: byte[] cipherText = c.doFinal(input.getBytes());
114: String retValue = new String(Hex.encodeHex(cipherText));
115: return retValue;
116: }
117:
118: public static String decrypt_AES_from_HEX(String input, String key)
119: throws IllegalBlockSizeException, BadPaddingException,
120: NoSuchAlgorithmException, NoSuchPaddingException,
121: InvalidKeyException {
122:
123: char[] chrs = input.toCharArray();
124: byte[] inputBytes;
125: try {
126: inputBytes = Hex.decodeHex(chrs);
127: } catch (Exception e) {
128: log.error("Cannot decodeHex", e);
129: throw new IllegalArgumentException(
130: "The input hex is not valid.");
131: }
132:
133: byte[] desKeyData = key.getBytes();
134: SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "AES");
135:
136: // get cipher object for password-based encryption
137: Cipher c = Cipher.getInstance("AES");
138:
139: c.init(Cipher.DECRYPT_MODE, secretKey);
140:
141: // Decrypt the ciphertext
142: byte[] cleartext = c.doFinal(inputBytes);
143: String retValue = new String(cleartext);
144: return retValue;
145: }
146:
147: /**
148: * This method just call URLEncoder.encode() with the default encoding is UTF-8
149: * @param input String
150: * @return String
151: */
152: public static String encodeURL(String input) {
153: try {
154: return URLEncoder.encode(input, "UTF-8");
155: } catch (UnsupportedEncodingException e) {
156: log.fatal("Assertion, should never happen", e);
157: throw new RuntimeException(
158: "System error invoking URLEncoder.encode()");
159: }
160: }
161:
162: /**
163: * This method just call URLDecoder.decode() with the default encoding UTF-8
164: * @param input String
165: * @return String
166: */
167: public static String decodeURL(String input) {
168: try {
169: return URLDecoder.decode(input, "UTF-8");
170: } catch (UnsupportedEncodingException e) {
171: log.fatal("Assertion, should never happen", e);
172: throw new RuntimeException(
173: "System error invoking URLDecoder.decode()");
174: }
175: }
176:
177: /**
178: * Filter a URL to make it safe, this method is used in class URLFilter
179: * @param url String a URL to be filtered
180: * @return String a URL that has been filtered
181: */
182: public static String filterUrl(String url) {
183: String lowerUrl = url.toLowerCase();
184: if ((lowerUrl.indexOf("javascript:") >= 0)
185: || lowerUrl.indexOf("file:") >= 0) {
186: return "";
187: }
188:
189: String protocol = "http://";//default protocol
190: String name = null;
191: if (url.startsWith("http://")) {
192: protocol = "http://";
193: name = url.substring(protocol.length());// must duplicate it because of the default protocol
194: } else if (url.startsWith("https://")) {
195: protocol = "https://";
196: name = url.substring(protocol.length());// must duplicate it because of the default protocol
197: } else if (url.startsWith("ftp://")) {
198: protocol = "ftp://";
199: name = url.substring(protocol.length());// must duplicate it because of the default protocol
200: } else if (url.startsWith("mailto:")) {
201: protocol = "mailto:";
202: name = url.substring(protocol.length());// must duplicate it because of the default protocol
203: } else {
204: name = url;
205: }
206: String ret;
207: if (protocol.equals("mailto:")) {
208: try {
209: MailUtil.checkGoodEmail(name);
210: ret = protocol + name;
211: } catch (Exception ex) {
212: ret = "";
213: }
214: } else {
215: ret = protocol + encodePath(name);
216: }
217: return ret;
218: }
219:
220: /**
221: *
222: * @param path the path, something like this localhost:8080/image/index.html
223: * @return the path after being encoded
224: */
225: public static String encodePath(String path) {
226: path = removeInvalidUserInURL(path);
227: path = removeJSessionIDInURL(path);
228: return path;
229: /*
230: String ret = "";
231: int indexFirstSlash = path.indexOf('/');
232: if ( indexFirstSlash != -1 ) {
233: String hostport = path.substring(0, indexFirstSlash);
234: int indexFirstColon = hostport.indexOf(':');
235: if (indexFirstColon != -1) {
236: String host = hostport.substring(0, indexFirstColon);
237: String port = hostport.substring(indexFirstColon + 1);
238: hostport = Encoder.encodeURL(host) + ":" + Encoder.encodeURL(port);
239: } else {
240: hostport = Encoder.encodeURL(hostport);
241: }
242: String filename = path.substring(indexFirstSlash + 1);
243: filename = Encoder.encodeURL(filename);
244: ret = hostport + "/" + filename;
245: } else {
246: ret = Encoder.encodeURL(path);
247: }
248: return ret;
249: */
250: }
251:
252: /**
253: * This method is used to fix IE spoof url bug:
254: * http://originalsite.com % 0 0 @ www.badsite.com
255: * <p>(remove the space above, I added spaces because
256: * McAfee conplain that it is a trojan)
257: * @param path String
258: * @return String
259: */
260: private static String removeInvalidUserInURL(String path) {
261: // atIndex is the RIGHT most of @
262: int atIndex = path.lastIndexOf('@');
263: if (atIndex != -1) {
264: // has the user info part
265: // percentIndex is the LEFT most of %
266: int pecentIndex = path.indexOf('%');
267: if ((pecentIndex != -1) && (pecentIndex < atIndex)) {
268: // user info part has % in it, very likely a spoof url
269: return path.substring(atIndex + 1);// get the char right after @
270: }
271: }
272: return path;
273: }
274:
275: /**
276: * @param path String
277: * @return String
278: */
279: private static String removeJSessionIDInURL(String path) {
280: // startIndex is the index of ;jsessionid=
281: // endIndex is the index of ?
282: int startIndex = path.indexOf(";jsessionid=");
283: if (startIndex != -1) {
284: int endIndex = path.indexOf('?');
285: if ((endIndex != -1)) {
286: return path.substring(0, startIndex)
287: + path.substring(endIndex);
288: } else {
289: return path.substring(0, startIndex);
290: }
291: }
292: return path;
293: }
294:
295: /*
296: public static void main(String[] args) {
297: //test data should be
298: //a1 iou3zTQ6oq2Zt9diAwhXog==
299: //Hello World sQqNsWTgdUEFt6mb5y4/5Q==
300:
301: //String testString = "a1";
302: //String encrypted = getMD5_Base64(testString);
303: //System.out.println("encrypted = " + encrypted);
304: //System.out.println("length = " + encrypted.length());
305:
306:
307: //String encodeString = "Di\u1ec5n \u0111\u00e0n";//Die^~n d-a`n
308: //JDK 1.3 result : Di%3Fn+%3F%E0n
309: //JDK 1.4 result : Di%E1%BB%85n+%C4%91%C3%A0n
310: //System.out.println("encodeURL input '" + encodeString + "' output '" + encodeURL(encodeString) + "'");
311:
312: //String decodeString = "Di%E1%BB%85n+%C4%91%C3%A0n";//encoded of "Die^~n d-a`n"
313: //System.out.println("decodeURL input '" + decodeString + "' output '" + decodeURL(decodeString) + "'");
314: }*/
315:
316: }
|