使用3DES用盐解密密码

时间:2011-10-26 09:06:17

标签: java

我有一个名为DESHelper的类,用于使用salt加密和解密密码。 Salt是该用户的用户名。但是这个类在解密时仍然失败。

我的课程:

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<String, byte[]> mKeys = new HashMap<String, byte[]>();

    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<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<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 <= 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>0 && 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<aSource_length) 
            {
                int i24=0;
                for (int bscan=0;bscan<4;bscan++) 
                {
                    if (i_ofs<aSource_length) 
                    {
                        int decode = decode(aSource.charAt(i_ofs));
                        if (decode==-1) return null;
                        i24=(i24<<6)+decode;
                    } 
                    else 
                    {
                        i24=i24<<6;
                    }

                    i_ofs++;
                }

                if (o_ofs<len) 
                {
                    result[o_ofs++]=(byte)(i24>>16);
                }

                if (o_ofs<len) 
                {
                    result[o_ofs++]=(byte)(i24>>8);
                }

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

        private int decode(char c)
        {
            if (c>='A' && c<='Z') 
            {
                return c-'A';
            }

            if (c>='a' && c<='z') 
            {
                return c-'a'+26;
            }

            if (c>='0' && c<='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<aSource.length) {

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

                    i_ofs++;
                }

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

}

我有例外:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher

在线:

final byte[] plainText = decipher.doFinal(message);
解密方法中的

我的测试方法:

 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"));

    }

也许我错过了什么?如果我有什么不对劲,请纠正我。感谢

2 个答案:

答案 0 :(得分:0)

这只是一种预感,但尝试使用二进制零填充输入,使其长度可被8整除。

答案 1 :(得分:0)

分组密码需要输入(用于解密)具有适当的长度(填充)。

使用更方便的CipherInputStreamCipherOutputStream类可以避免这种错误。

相关问题