001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: StringEncryptor.java 3718 2007-04-17 11:18:17Z gbevin $
007: *
008: * Obfuscation code Copyright (c) 1998 Mort Bay Consulting (Australia) Pty. Ltd.
009: */
010: package com.uwyn.rife.tools;
011:
012: import com.uwyn.rife.datastructures.EnumClass;
013: import java.security.MessageDigest;
014: import java.security.NoSuchAlgorithmException;
015:
016: public class StringEncryptor extends EnumClass<String> {
017: private static final String IDENTIFIER_HEX_SUFFIX = "HEX";
018:
019: public static final String IDENTIFIER_OBF = "OBF";
020: public static final String IDENTIFIER_MD5 = "MD5";
021: public static final String IDENTIFIER_MD5HEX = IDENTIFIER_MD5
022: + IDENTIFIER_HEX_SUFFIX;
023: public static final String IDENTIFIER_SHA = "SHA";
024: public static final String IDENTIFIER_SHAHEX = IDENTIFIER_SHA
025: + IDENTIFIER_HEX_SUFFIX;
026: public static final String IDENTIFIER_WHIRLPOOL = "WRP";
027: public static final String IDENTIFIER_WHIRLPOOLHEX = IDENTIFIER_WHIRLPOOL
028: + IDENTIFIER_HEX_SUFFIX;
029:
030: private static final String PREFIX_SEPERATOR_SUFFIX = ":";
031: private static final String PREFIX_OBF = IDENTIFIER_OBF
032: + PREFIX_SEPERATOR_SUFFIX;
033: private static final String PREFIX_MD5 = IDENTIFIER_MD5
034: + PREFIX_SEPERATOR_SUFFIX;
035: private static final String PREFIX_MD5HEX = IDENTIFIER_MD5HEX
036: + PREFIX_SEPERATOR_SUFFIX;
037: private static final String PREFIX_SHA = IDENTIFIER_SHA
038: + PREFIX_SEPERATOR_SUFFIX;
039: private static final String PREFIX_SHAHEX = IDENTIFIER_SHAHEX
040: + PREFIX_SEPERATOR_SUFFIX;
041: private static final String PREFIX_WHIRLPOOL = IDENTIFIER_WHIRLPOOL
042: + PREFIX_SEPERATOR_SUFFIX;
043: private static final String PREFIX_WHIRLPOOLHEX = IDENTIFIER_WHIRLPOOLHEX
044: + PREFIX_SEPERATOR_SUFFIX;
045:
046: public static final StringEncryptor OBF = new StringEncryptor(
047: PREFIX_OBF);
048: public static final StringEncryptor MD5 = new StringEncryptor(
049: PREFIX_MD5);
050: public static final StringEncryptor MD5HEX = new StringEncryptor(
051: PREFIX_MD5HEX);
052: public static final StringEncryptor SHA = new StringEncryptor(
053: PREFIX_SHA);
054: public static final StringEncryptor SHAHEX = new StringEncryptor(
055: PREFIX_SHAHEX);
056: public static final StringEncryptor WHIRLPOOL = new StringEncryptor(
057: PREFIX_WHIRLPOOL);
058: public static final StringEncryptor WHIRLPOOLHEX = new StringEncryptor(
059: PREFIX_WHIRLPOOLHEX);
060:
061: private StringEncryptor(String identifier) {
062: super (identifier);
063: }
064:
065: public static StringEncryptor getEncryptor(String identifier) {
066: return getMember(StringEncryptor.class, identifier
067: + PREFIX_SEPERATOR_SUFFIX);
068: }
069:
070: public String encrypt(String value) throws NoSuchAlgorithmException {
071: if (null == value)
072: throw new IllegalArgumentException("value can't be null");
073:
074: return autoEncrypt(mIdentifier + value);
075: }
076:
077: private static String encodeBase64(byte[] bytes) {
078: return Base64.encodeToString(bytes, false);
079: }
080:
081: private static String encodeHex(byte[] bytes) {
082: StringBuilder sb = new StringBuilder();
083: for (int i = 0; i < bytes.length; ++i) {
084: sb.append(Integer.toHexString((bytes[i] & 0xFF) | 0x100)
085: .substring(1, 3));
086: }
087: return sb.toString();
088: }
089:
090: public static String autoEncrypt(String value)
091: throws NoSuchAlgorithmException {
092: if (null == value)
093: throw new IllegalArgumentException("value can't be null");
094:
095: if (value.startsWith(PREFIX_OBF)) {
096: return PREFIX_OBF
097: + obfuscate(value.substring(PREFIX_OBF.length()));
098: } else {
099: boolean encode_base64 = false;
100: String prefix = null;
101: byte[] bytes = null;
102: if (value.startsWith(PREFIX_SHA)
103: || value.startsWith(PREFIX_SHAHEX)) {
104: if (value.startsWith(PREFIX_SHA)) {
105: prefix = PREFIX_SHA;
106: encode_base64 = true;
107: } else {
108: prefix = PREFIX_SHAHEX;
109: encode_base64 = false;
110: }
111: MessageDigest digest = MessageDigest.getInstance("SHA");
112: digest.update(value.substring(prefix.length())
113: .getBytes());
114: bytes = digest.digest();
115: } else if (value.startsWith(PREFIX_WHIRLPOOL)
116: || value.startsWith(PREFIX_WHIRLPOOLHEX)) {
117: if (value.startsWith(PREFIX_WHIRLPOOL)) {
118: prefix = PREFIX_WHIRLPOOL;
119: encode_base64 = true;
120: } else {
121: prefix = PREFIX_WHIRLPOOLHEX;
122: encode_base64 = false;
123: }
124: Whirlpool whirlpool = new Whirlpool();
125: whirlpool.NESSIEinit();
126: whirlpool.NESSIEadd(value.substring(prefix.length()));
127: byte[] digest = new byte[Whirlpool.DIGESTBYTES];
128: whirlpool.NESSIEfinalize(digest);
129: bytes = digest;
130: } else if (value.startsWith(PREFIX_MD5)
131: || value.startsWith(PREFIX_MD5HEX)) {
132: if (value.startsWith(PREFIX_MD5)) {
133: prefix = PREFIX_MD5;
134: encode_base64 = true;
135: } else {
136: prefix = PREFIX_MD5HEX;
137: encode_base64 = false;
138: }
139: MessageDigest digest = MessageDigest.getInstance("MD5");
140: digest.update(value.substring(prefix.length())
141: .getBytes());
142: bytes = digest.digest();
143: } else {
144: return value;
145: }
146:
147: if (encode_base64) {
148: value = prefix + encodeBase64(bytes);
149: } else {
150: value = prefix + encodeHex(bytes);
151: }
152: }
153:
154: assert value != null;
155:
156: return value;
157: }
158:
159: public static boolean matches(String checkedValue,
160: String encryptedValue) throws NoSuchAlgorithmException {
161: if (null == checkedValue)
162: throw new IllegalArgumentException(
163: "checkedValue can't be null");
164: if (null == encryptedValue)
165: throw new IllegalArgumentException(
166: "encryptedValue can't be null");
167:
168: return encryptedValue.equals(adaptiveEncrypt(checkedValue,
169: encryptedValue));
170: }
171:
172: public static String adaptiveEncrypt(String clearValue,
173: String encryptedValue) throws NoSuchAlgorithmException {
174: if (null == clearValue)
175: throw new IllegalArgumentException(
176: "clearValue can't be null");
177: if (null == encryptedValue)
178: throw new IllegalArgumentException(
179: "encryptedValue can't be null");
180:
181: if (encryptedValue.startsWith(PREFIX_OBF)) {
182: clearValue = PREFIX_OBF + clearValue;
183: } else if (encryptedValue.startsWith(PREFIX_WHIRLPOOL)) {
184: clearValue = PREFIX_WHIRLPOOL + clearValue;
185: } else if (encryptedValue.startsWith(PREFIX_WHIRLPOOLHEX)) {
186: clearValue = PREFIX_WHIRLPOOLHEX + clearValue;
187: } else if (encryptedValue.startsWith(PREFIX_MD5)) {
188: clearValue = PREFIX_MD5 + clearValue;
189: } else if (encryptedValue.startsWith(PREFIX_MD5HEX)) {
190: clearValue = PREFIX_MD5HEX + clearValue;
191: } else if (encryptedValue.startsWith(PREFIX_SHA)) {
192: clearValue = PREFIX_SHA + clearValue;
193: } else if (encryptedValue.startsWith(PREFIX_SHAHEX)) {
194: clearValue = PREFIX_SHAHEX + clearValue;
195: }
196:
197: return autoEncrypt(clearValue);
198: }
199:
200: public static String obfuscate(String value) {
201: if (null == value)
202: throw new IllegalArgumentException("value can't be null");
203:
204: StringBuilder buffer = new StringBuilder();
205: byte[] bytes = value.getBytes();
206: for (int i = 0; i < bytes.length; i++) {
207: byte b1 = bytes[i];
208: byte b2 = bytes[value.length() - (i + 1)];
209: int i1 = (int) b1 + (int) b2 + 127;
210: int i2 = (int) b1 - (int) b2 + 127;
211: int i0 = i1 * 256 + i2;
212: String x = Integer.toString(i0, 36);
213:
214: switch (x.length()) {
215: case 1:
216: buffer.append('0');
217: case 2:
218: buffer.append('0');
219: case 3:
220: buffer.append('0');
221: default:
222: buffer.append(x);
223: }
224: }
225:
226: return buffer.toString();
227: }
228:
229: public static String deobfuscate(String value) {
230: if (null == value)
231: throw new IllegalArgumentException("value can't be null");
232:
233: if (value.startsWith(PREFIX_OBF)) {
234: value = value.substring(PREFIX_OBF.length());
235: }
236:
237: byte[] bytes = new byte[value.length() / 2];
238: int l = 0;
239:
240: for (int i = 0; i < value.length(); i += 4) {
241: String x = value.substring(i, i + 4);
242: int i0 = Integer.parseInt(x, 36);
243: int i1 = (i0 / 256);
244: int i2 = (i0 % 256);
245: bytes[l++] = (byte) ((i1 + i2 - 254) / 2);
246: }
247:
248: return new String(bytes, 0, l);
249: }
250:
251: public static void main(String[] arguments) {
252: boolean valid_arguments = true;
253: if (arguments.length < 1 || arguments.length > 3) {
254: valid_arguments = false;
255: } else if (!arguments[0].startsWith("-")) {
256: if (arguments.length > 1) {
257: valid_arguments = false;
258: }
259: } else {
260: if (!arguments[0].equals("-e")
261: && !arguments[0].equals("-d")
262: && !arguments[0].equals("-c")) {
263: valid_arguments = false;
264: } else if (!arguments[0].equals("-c")
265: && 3 == arguments.length) {
266: valid_arguments = false;
267: }
268: }
269:
270: if (!valid_arguments) {
271: System.err.println("Usage : java "
272: + StringEncryptor.class.getName()
273: + " [-edc] string {encrypted}");
274: System.err.println("Encrypts strings for usage with RIFE.");
275: System.err.println(" -e encrypt a string (default)");
276: System.err
277: .println(" -d decrypt a string if the algorithm support it");
278: System.err
279: .println(" -c check the validity of the string against an encrypted version");
280: System.exit(1);
281: }
282: try {
283: if (1 == arguments.length) {
284: System.err.println(autoEncrypt(arguments[0]));
285: System.exit(0);
286: } else if (arguments[0].equals("-e")) {
287: System.err.println(autoEncrypt(arguments[1]));
288: System.exit(0);
289: }
290: if (arguments[0].equals("-d")) {
291: if (arguments[1].startsWith(PREFIX_OBF)) {
292: System.err.println(deobfuscate(arguments[1]));
293: } else {
294: System.err
295: .println("ERROR: the algorithm doesn't support decoding.");
296: }
297: System.exit(0);
298: }
299: if (arguments[0].equals("-c")) {
300: if (matches(arguments[1], arguments[2])) {
301: System.err.println("VALID: the strings match.");
302: } else {
303: System.err
304: .println("INVALID: the strings don't match.");
305: }
306: System.exit(0);
307: }
308: } catch (NoSuchAlgorithmException e) {
309: e.printStackTrace();
310: }
311: }
312: }
|