package com.mcxiaoke.minicat.util; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.util.Log; import com.mcxiaoke.minicat.AppContext; import org.apache.http.protocol.HTTP; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.security.MessageDigest; import java.security.SecureRandom; /** * @author mcxiaoke * @version 1.0 2011.12.09 */ public final class CryptoHelper { private static final String TAG = CryptoHelper.class.getSimpleName(); private static final String EncodeAlgorithm = "DES"; private static final String HEX = "0123456789ABCDEF"; private static final String SECURE_KEY = "g$#Tdg%$^mc[54jxiaoke"; private static CryptoHelper instance = null; private SecretKey key = null; public static CryptoHelper getInstance() { if (instance == null) { instance = new CryptoHelper(); if (!instance.init()) { instance = null; } } return instance; } public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toHex(result); } public static String decrypt(String seed, String encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = encrypted.getBytes(); byte[] result = decrypt(rawKey, enc); return new String(result); } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); } private static byte[] toByte(String hexString) { int len = hexString.length() / 2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue(); return result; } private static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2 * buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } public static String rot13(String text) { if (text == null) { return ""; } final StringBuilder result = new StringBuilder(); // plaintext flag (do not convert) boolean plaintext = false; final int length = text.length(); int c; int capitalized; for (int index = 0; index < length; index++) { c = text.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; } result.append((char) c); } return result.toString(); } public static String md5(String text) { String hashed = ""; try { final MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(text.getBytes(HTTP.UTF_8), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { Log.e(TAG, "cgBase.md5: " + e.toString()); } return hashed; } public static String sha1(String text) { String hashed = ""; try { final MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { Log.e(TAG, "cgBase.sha1: " + e.toString()); } return hashed; } public static byte[] hashHmac(String text, String salt) { byte[] macBytes = {}; try { final SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(), "HmacSHA1"); final Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKeySpec); macBytes = mac.doFinal(text.getBytes()); } catch (Exception e) { Log.e(TAG, "cgBase.hashHmac: " + e.toString()); } return macBytes; } public static CharSequence rot13(final Spannable span) { // I needed to re-implement the rot13(String) encryption here because we must work on // a SpannableStringBuilder instead of the pure text and we must replace each character inline. // Otherwise we loose all the images, colors and so on... final SpannableStringBuilder buffer = new SpannableStringBuilder(span); boolean plaintext = false; final int length = span.length(); int c; int capitalized; for (int index = 0; index < length; index++) { c = span.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; } buffer.replace(index, index + 1, String.valueOf((char) c)); } return buffer; } public static String convertToGcBase31(final String gccode) { final String alphabet = "0123456789ABCDEFGHJKMNPQRTVWXYZ"; if (null == gccode) { return ""; } char[] characters = gccode.toUpperCase().toCharArray(); if (characters.length <= 2) { return ""; } final int base = (characters.length <= 5 || (characters.length == 6 && alphabet.indexOf(characters[2]) < 16)) ? 16 : 31; int result = 0; for (int i = 2; i < characters.length; i++) { result *= base; result += alphabet.indexOf(characters[i]); } if (31 == base) { result += Math.pow(16, 4) - 16 * Math.pow(31, 3); } return Integer.toString(result); } private boolean init() { try { DESKeySpec desKeySpec = new DESKeySpec(SECURE_KEY.getBytes()); SecretKeyFactory skf = SecretKeyFactory .getInstance(EncodeAlgorithm); key = skf.generateSecret(desKeySpec); } catch (Exception e) { if (AppContext.DEBUG) e.printStackTrace(); } return key != null; } @SuppressWarnings("unused") private boolean init2() { try { KeyGenerator keygen = KeyGenerator.getInstance(EncodeAlgorithm); SecureRandom random = new SecureRandom(); keygen.init(random); key = keygen.generateKey(); } catch (Exception e) { e.printStackTrace(); } return key != null; } private Cipher getCipher(int mode) { try { Cipher cipher = Cipher.getInstance(EncodeAlgorithm); cipher.init(mode, key); return cipher; } catch (Exception e) { if (AppContext.DEBUG) e.printStackTrace(); } return null; } private Cipher getEncodeCipher() { return this.getCipher(Cipher.ENCRYPT_MODE); } private Cipher getDecodeCipher() { return this.getCipher(Cipher.DECRYPT_MODE); } /** * 解密,若输入为null或加/解密过程出现异常,则输出为null <br/> * 作者:wallimn 时间:2009-8-12 上午08:09:44<br/> * 博客:http://wallimn.iteye.com<br/> * 参数:<br/> * * @param str * @return */ public String decode(String str) { if (str == null) return null; Cipher cipher = getDecodeCipher(); StringBuffer sb = new StringBuffer(); int blockSize = cipher.getBlockSize(); int outputSize = cipher.getOutputSize(blockSize); byte[] src = stringToBytes(str); byte[] outBytes = new byte[outputSize]; int i = 0; try { for (; i <= src.length - blockSize; i = i + blockSize) { int outLength = cipher.update(src, i, blockSize, outBytes); sb.append(new String(outBytes, 0, outLength)); } if (i == src.length) outBytes = cipher.doFinal(); else { outBytes = cipher.doFinal(src, i, src.length - i); } sb.append(new String(outBytes)); return sb.toString(); } catch (Exception e) { if (AppContext.DEBUG) e.printStackTrace(); } return null; } /** * 加密,若输入为null或加/解密过程出现异常,则输出为null <br/> * 作者:wallimn 时间:2009-8-12 上午08:09:59<br/> * 博客:http://wallimn.iteye.com<br/> * 参数:<br/> * * @param str * @return */ public String encode(String str) { if (str == null) return null; Cipher cipher = getEncodeCipher(); StringBuffer sb = new StringBuffer(); int blockSize = cipher.getBlockSize(); int outputSize = cipher.getOutputSize(blockSize); byte[] src = str.getBytes(); byte[] outBytes = new byte[outputSize]; int i = 0; try { for (; i <= src.length - blockSize; i = i + blockSize) { int outLength = cipher.update(src, i, blockSize, outBytes); sb.append(bytesToString(outBytes, outLength)); } if (i == src.length) outBytes = cipher.doFinal(); else { outBytes = cipher.doFinal(src, i, src.length - i); } sb.append(bytesToString(outBytes)); return sb.toString(); } catch (Exception e) { if (AppContext.DEBUG) e.printStackTrace(); } return null; } private String bytesToString(byte[] bs) { if (bs == null || bs.length == 0) return ""; return bytesToString(bs, bs.length); } private String bytesToString(byte[] bs, int len) { if (bs == null || bs.length == 0) return ""; StringBuffer sb = new StringBuffer(); for (int i = 0; i < len; i++) { // System.out.println(bs[i]+":"+String.format("%02X", bs[i])); sb.append(String.format("%02X", bs[i])); } return sb.toString(); } private byte[] stringToBytes(String str) { if (str == null || str.length() < 2 || str.length() % 2 != 0) return new byte[0]; int len = str.length(); byte[] bs = new byte[len / 2]; for (int i = 0; i * 2 < len; i++) { bs[i] = (byte) (Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16) & 0xFF); // System.out.println(str.substring(i * 2, i * 2 + 2)+":"+bs[i]); } return bs; } }