Decrypt password with salt using 3DES
<p>I have a class named DESHelper that used to encrypt and decrypt password with a salt. Salt is username of that user. But this class still fail when it decrypt.</p>

<p>My class:</p>

<pre><code>public class DESHelper {

    private String keyPass = "KeyPass";
    private String keyAlias = "keyAlias";
    private String keyStorePass="keyStorePass";
    private KeyStore ks = null;
    private static final String KEYSTORE_PATH = "keystore/mykeystore.keystore";
    private static final String KEYSTORE_TYPE = "jceks";    
    protected static String DES_KEY = "pin";
    private Map&lt;String, byte[]&gt; mKeys = new HashMap&lt;String, byte[]&gt;();

    public String decrypt(byte[] message, String salt) throws Exception {

        SecretKey secretKey = getSecretKey();

        if (secretKey == null) 
        {
            throw new GeneralSecurityException("No secret key");
        }

        final IvParameterSpec iv = new IvParameterSpec(generateIV(keyAlias, salt, DES_KEY));
        final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        decipher.init(Cipher.DECRYPT_MODE, secretKey, iv);

        final byte[] plainText = decipher.doFinal(message);

        return new String(plainText, "UTF-8");
    }

    public String encrypt(String value, String salt) {

        byte ciphertext[][] = new byte[2][];

        try
        {           
            SecretKey secretKey = getSecretKey();

            if (secretKey == null) 
            {
                throw new GeneralSecurityException("No secret key");
            }

            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            byte iv[] = generateIV(keyAlias, salt, DES_KEY);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
            ciphertext[0] = cipher.update(stringToByteArray(value));
            ciphertext[1] = cipher.doFinal(generateMAC(keyAlias, salt, DES_KEY, value));
        }
        catch (GeneralSecurityException gse) 
        {
            gse.printStackTrace();
            return null;
        }

        if (ciphertext[0] == null) 
        {
            ciphertext[0] = new byte[0];
        }

        if (ciphertext[1] == null) 
        {
            ciphertext[1] = new byte[0];
        }

        byte ct[] = new byte[ciphertext[0].length + ciphertext[1].length];
        System.arraycopy(ciphertext[0], 0, ct, 0, ciphertext[0].length);
        System.arraycopy(ciphertext[1], 0, ct, ciphertext[0].length, ciphertext[1].length);

        // Convert encrypted bytes to a String
        StringBuffer result = new StringBuffer(2 * ct.length + 1);
        result.append("b");           // first byte indicates encoding method.
        Base64 enc = new Base64();
        result.append(enc.encode(ct));

        return result.toString();
    }

    /**
     * 
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws GeneralSecurityException 
     */
    public SecretKey getSecretKey() throws InvalidKeyException, NoSuchAlgorithmException, GeneralSecurityException{

        byte des_key[];
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede") ;

        if (secretKeyFactory == null) 
        {
            throw new GeneralSecurityException("No DESede factory");
        }

        try
        {
            des_key = getKey(keyAlias);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return null;
        }

        SecretKey secretKey = secretKeyFactory.generateSecret(new DESedeKeySpec(des_key));

        return secretKey;
    }

    /**
     * Generate MAC
     */
    protected byte[] generateMAC(String type,String salt,String key,String value) {
        try 
        {
            MessageDigest md = MessageDigest.getInstance("SHA-1");

            if (type!=null) {
                md.update(stringToByteArray(type));
            }

            if (salt!=null) {
                md.update(stringToByteArray(salt));
            }

            if (key!=null) {
                md.update(stringToByteArray(key));
            }

            if (value!=null) {
                md.update(stringToByteArray(value));
            }

            byte[] sha = md.digest();
            byte[] mac = new byte[4];

            for (int scan=0;scan&lt;sha.length;scan++) 
            {
                mac[scan%4]=(byte)(mac[scan%4]^sha[scan]);
            }

            return mac;
        } 
        catch (NoSuchAlgorithmException ex) 
        {
            throw new IllegalStateException(ex.getMessage());
        }
    }

    protected byte[] generateIV(String type,String salt,String key) {
        try 
        {
            MessageDigest md = MessageDigest.getInstance("SHA-1");

            if (type!=null) {
                md.update(stringToByteArray(type));
            }

            if (salt!=null) {
                md.update(stringToByteArray(salt));
            }

            if (key!=null) {
                md.update(stringToByteArray(key));
            }

            byte[] sha = md.digest();
            byte[] iv = new byte[8];

            for (int scan=0;scan&lt;sha.length;scan++) 
            {
                iv[scan%8]=(byte)(iv[scan%8]^sha[scan]);
            }

            return iv;
        } 
        catch (NoSuchAlgorithmException ex) 
        {
            throw new IllegalStateException(ex.getMessage());
        }
    }

    protected byte[] getKey(String alias) throws GeneralSecurityException, IOException {

        synchronized (mKeys) 
        {
            byte k[] = mKeys.get(alias);
            if (k != null) {
                return k;
            }
        }

        byte key[] = getKeystoreKey(alias, 192);

        if (key == null) 
        {
            return null;
        }

        if (key.length != 24) {
            return null;
        }

        synchronized (mKeys) 
        {
            mKeys.put(alias, key);
            return key;
        }
    }

    protected byte[] stringToByteArray(String aString) {
        try 
        {
            return aString.getBytes("UTF-8");
        } 
        catch (java.io.UnsupportedEncodingException ex) 
        {
            System.out.println("Exception in stringToByteArray " + ex.getMessage());
            return null;
        }
    }

    /**
    * Returns String From An Array Of Bytes
    */
    private String bytes2String(byte[] bytes) {

        StringBuffer stringBuffer = new StringBuffer();

        for (int i = 0; i &lt;= bytes.length; i++) 
        {
            stringBuffer.append((char) bytes[i]);
        }

        return stringBuffer.toString();

    }


    protected byte[] getKeystoreKey(String aKeyName,int size) throws GeneralSecurityException, IOException {

        Key key = getKeystore().getKey(aKeyName, keyPass.toCharArray());

        if (key==null) 
        {
            System.out.println("KeyStore key "+aKeyName+" not found");
            return null;
        }

        byte keyBytes[] = key.getEncoded();

        if (keyBytes.length != (size/8) ) 
        {
            System.out.println("KeyStore key "+aKeyName+" invalid length. Expected:"+size+" was: "+(keyBytes.length*8));
            return null;
        }

        return keyBytes;
    }

    protected KeyStore getKeystore() throws GeneralSecurityException, IOException {
        if ( ks == null )
        {
            ks = KeyStore.getInstance(KEYSTORE_TYPE);
            char[] password = keyStorePass.toCharArray();

            if (password == null) 
            {
                System.out.println("Couldn't get keystore password from config");
            }

            // get the keystore as a resource
            InputStream is = getClass().getClassLoader().getResourceAsStream(KEYSTORE_PATH);

            try
            {
                ks.load(is, password);
            }
            finally
            {
                if (is != null)
                {
                    is.close();
                }
            }
        }

        return ks;
    }

    public class Base64 {
        private char sBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();

        /** Creates a new instance of Base64 */
        public Base64()
        {
        }

        public byte[] decode(String aSource)
        {
            int aSource_length=aSource.length();

            while (aSource_length&gt;0 &amp;&amp; aSource.charAt(aSource_length-1)=='=') aSource_length--;

            if (aSource_length%4==1) 
            {
                return null;
            }

            int len = (aSource_length/4)*3 + aSource_length%4 - (aSource_length%4==0?0:1);
            byte result[] = new byte[len];

            int o_ofs=0;
            int i_ofs=0;

            while (i_ofs&lt;aSource_length) 
            {
                int i24=0;
                for (int bscan=0;bscan&lt;4;bscan++) 
                {
                    if (i_ofs&lt;aSource_length) 
                    {
                        int decode = decode(aSource.charAt(i_ofs));
                        if (decode==-1) return null;
                        i24=(i24&lt;&lt;6)+decode;
                    } 
                    else 
                    {
                        i24=i24&lt;&lt;6;
                    }

                    i_ofs++;
                }

                if (o_ofs&lt;len) 
                {
                    result[o_ofs++]=(byte)(i24&gt;&gt;16);
                }

                if (o_ofs&lt;len) 
                {
                    result[o_ofs++]=(byte)(i24&gt;&gt;8);
                }

                if (o_ofs&lt;len) 
                {
                    result[o_ofs++]=(byte)(i24);
                }
            }
            return result;
        }

        private int decode(char c)
        {
            if (c&gt;='A' &amp;&amp; c&lt;='Z') 
            {
                return c-'A';
            }

            if (c&gt;='a' &amp;&amp; c&lt;='z') 
            {
                return c-'a'+26;
            }

            if (c&gt;='0' &amp;&amp; c&lt;='9') 
            {
                return c-'0'+52;
            }

            if (c=='+') 
            {
                return 62;
            }

            if (c=='/') 
            {
                return 63;
            }

            return -1;
        }

        public String encode(byte[] aSource)
        {
            int result_length = aSource.length*4/3 + (aSource.length%3==0?0:1);

            char result[]=new char[ ((aSource.length+2)/3)*4 ];

            int o_ofs=0;
            int i_ofs=0;

            while (i_ofs&lt;aSource.length) {

                int i24=0;
                for (int bscan=0;bscan&lt;3;bscan++) {
                    if (i_ofs&gt;=aSource.length) {
                        i24=i24&lt;&lt;8;
                    } 
                    else {
                        i24=(i24&lt;&lt;8)+(aSource[i_ofs]&amp;0xff);
                    }

                    i_ofs++;
                }

                if (o_ofs&lt;result_length) result[o_ofs++]=sBase64[(i24&gt;&gt;18)&amp;63];
                if (o_ofs&lt;result_length) result[o_ofs++]=sBase64[(i24&gt;&gt;12)&amp;63];
                if (o_ofs&lt;result_length) result[o_ofs++]=sBase64[(i24&gt;&gt;6)&amp;63];
                if (o_ofs&lt;result_length) result[o_ofs++]=sBase64[(i24)&amp;63];
            }
            while (o_ofs&lt;result.length) result[o_ofs++]='=';
            return new String(result);
        }
    }

}
</code></pre>

<p>I got exception:</p>

<pre><code>javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
</code></pre>

<p>at line:</p>

<pre><code>final byte[] plainText = decipher.doFinal(message);
</code></pre>

<p>in decrypt method. </p>

<p>My test method:</p>

<pre><code> public static void main(String args[]) throws Exception {
        DESHelper des = new DESHelper();
        String encryptedStr = des.encrypt("admin", "admin");
        DESHelper.Base64 base64 = des.new Base64();

        System.out.println("Encrypted String: " + encryptedStr);            
        System.out.println("Decrypted String"   + des.decrypt(encryptedStr.getBytes(), "admin"));

    }
</code></pre>

<p>Maybe I missing something? Correct me if I have something wrong. Thanks</p>
