由于前段时间开发需要,要实现企业通过微信支付到个人银行卡的功能,现在整理一下,里面的极大部分代码是一位大神写好的,然后自己在基础上列出了123,如果有什么不好的地方望指出,以备后期改进,谢谢!!!

开发步骤:

一,准备工作




1.商户(企业)入驻微信,即在微信的商户平台进行注册


2.获取:mch_id(商户号),key(就是你商户平台设置的密钥key)


3.商户在产品中心,开通企业付款到个人银行卡功能


4.获取证书,微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载


  注:下载下来后,需要安装,商户证书调用或安装都需要使用到密码,该密码的值为微信商户号(mch_id), 其中的apiclient_cert.p12是商户证书文件,java开发仅使用此证书文件。


5.商户充值




二,开发


 1.需要的jar包


commons-codec-1.9.jar,commons-logging-1.1.3.jar,fluent-hc-4.3.4.jar,httpclient-4.5.jar,httpclient-cache-4.3.4.jar,


httpcore-4.4.1.jar,httpmime-4.3.4.jar,javabase64-1.3.1.jar,jdom-1.0.jar,servlet-api.jar,sun.misc.BASE64Decoder.jar,


xml-apis-1.0.b2.jar




 2.需要的配置参数


 


 public class WChatInfo {


//微信商户的id


public static final String MCH_ID = "1480911042";


//微信商户的key  签名使用


public static final String KEY="1bKk1wpnRbT2seZKOM2GEWoSJSoL1SRF";


public static final String  CHARSET = "UTF-8";//编码格式


//证书url


public static final String CA_LICENSE =  "E:" + File.separator + "pay"


+ File.separator + "cert" + File.separator + "apiclient_cert.p12";




}


 




  3.获取商户号的公钥


  调用的接口:https://fraud.mch.weixin.qq.com/risk/getpublickey


  请求参数:

mch_id,nonce_str(长度小于32位的随机字符串),sign(签名),sign_type(签名类型:MD5)


  请求方式:post


  


  public class GetPublicKey {


public String getPublicKey() throws Exception {


SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();


String nonce_str = StringUtils1.getStrRandom(28);//获取随机字符串


parameters.put("mch_id", WChatInfo.MCH_ID);


parameters.put("nonce_str", nonce_str);


parameters.put("sign_type", "MD5");


// 创建签名


String sign = SignUtils.creatSign(WChatInfo.CHARSET, parameters);


System.out.println(sign);




TreeMap<String, String> tmap = new TreeMap<String, String>();


tmap.put("mch_id", WChatInfo.MCH_ID);


tmap.put("nonce_str", nonce_str);


tmap.put("sign_type", "MD5");


tmap.put("sign", sign);


String xml = XMLUtils.getRequestXml(tmap);//将请求参数转换为请求报文


        //带证书请求


String xml1 = HttpClientCustomSSL.httpClientResultGetPublicKey(xml);//发送http的post请求获取公钥报文


String publicKey = XMLUtils.Progress_resultParseXml(xml1);//解析腾迅返回的公钥xml并获取公钥元素


return publicKey;




}


}


/**


 *获取随机字符串


 **/


public class StringUtils1 {


/**


* 获取随机字符串


* @param length 生成的随机字符串长度


* */


public static String getStrRandom(int length){


if(length<1){


return "";


}else{


String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";


StringBuilder sb = new StringBuilder();


Random ra = new Random();


int index = 0;


for (int i = 0; i < length ;i++ ) {


index = ra.nextInt(str.length());


sb.append(str.charAt(index));


}


return sb.toString();


}


}


}


/**


 *创建签名


 **/


public class SignUtils {




/**


* @param characterEncoding 编码格式 utf-8


* */


public static String creatSign(String characterEncoding,


SortedMap<Object, Object> parameters) {


StringBuffer sb = new StringBuffer();


Set es = parameters.entrySet();


Iterator it = es.iterator();


while(it.hasNext()) {


Map.Entry entry = (Map.Entry)it.next();


String k = (String)entry.getKey();


Object v = entry.getValue();


if(null != v && !"".equals(v) 


&& !"sign".equals(k) && !"key".equals(k)) {


sb.append(k + "=" + v + "&");


}


}


sb.append("key=" + WChatInfo.KEY);


String sign = MD5Utils.MD5Encode(sb.toString(), characterEncoding).toUpperCase();


System.out.println(sign);


return sign;


}


}


/**


 *MD5加密


 **/


public class MD5Utils {




private static String byteArrayToHexString(byte b[]) {


StringBuffer resultSb = new StringBuffer();


for (int i = 0; i < b.length; i++)


resultSb.append(byteToHexString(b[i]));




return resultSb.toString();


}




private static String byteToHexString(byte b) {


int n = b;


if (n < 0)


n += 256;


int d1 = n / 16;


int d2 = n % 16;


return hexDigits[d1] + hexDigits[d2];


}




public static String MD5Encode(String origin, String charsetname) {


String resultString = null;


try {


resultString = new String(origin);


MessageDigest md = MessageDigest.getInstance("MD5");


if (charsetname == null || "".equals(charsetname))


resultString = byteArrayToHexString(md.digest(resultString


.getBytes()));


else


resultString = byteArrayToHexString(md.digest(resultString


.getBytes(charsetname)));


} catch (Exception exception) {


}


return resultString;


}




private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",


"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };




}




/**


 *将请求参数转换为请求报文和解析腾迅返回的公钥xml并获取公钥元素


 **/


public class XMLUtils {


/**


* 将请求参数转换为请求报文


*/


@SuppressWarnings("rawtypes")


public static String getRequestXml(TreeMap<String, String> parameters)


throws Exception {


StringBuffer sb = new StringBuffer();


sb.append("<xml>");


Set es = parameters.entrySet();


Iterator it = es.iterator();


while (it.hasNext()) {


Map.Entry entry = (Map.Entry) it.next();


String k = (String) entry.getKey();


String v = (String) entry.getValue();


if ("mch_id".equalsIgnoreCase(k) || "nonce_str".equalsIgnoreCase(k)


|| "sign".equalsIgnoreCase(k)) {


sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");


} else {


sb.append("<" + k + ">" + v + "</" + k + ">");


}


}


sb.append("</xml>");


return sb.toString();


}


/**


* 解析腾迅返回的公钥xml并获取公钥元素


* @param xml


* @return


*/


@SuppressWarnings("unchecked")


public static String Progress_resultParseXml(String xml) {


String publicKey = null;


try {


StringReader read = new StringReader(xml);




InputSource source = new InputSource(read);




SAXBuilder sb = new SAXBuilder();




org.jdom.Document doc;


doc = (org.jdom.Document) sb.build(source);




org.jdom.Element root = doc.getRootElement();


List<org.jdom.Element> list = root.getChildren();




if (list != null && list.size() > 0) {


for (org.jdom.Element element : list) {


if("pub_key".equals(element.getName())){


publicKey=element.getText();


}


}


}




} catch (IOException e) {


e.printStackTrace();


} catch (Exception e) {


e.printStackTrace();


}


return publicKey;


}


}


/**


 * 发送公钥的http请求以及企业支付到银行卡的http请求


 * 


 * */


public class HttpClientCustomSSL {


/**


* httpClient 请求获取公钥


* @param parms


* @return  


* @throws Exception


*/


public static String httpClientResultGetPublicKey(String xml) throws Exception{


StringBuffer reultBuffer = new StringBuffer();




SSLConnectionSocketFactory sslsf = ReadSSl.getInstance().readCustomSSL();




HttpPost httpPost = new HttpPost("https://fraud.mch.weixin.qq.com/risk/getpublickey");


        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();


        StringEntity myEntity = new org.apache.http.entity.StringEntity(xml,WChatInfo.CHARSET);


        myEntity.setContentType("text/xml;charset=UTF-8");


        myEntity.setContentEncoding(WChatInfo.CHARSET);


        httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");


        httpPost.setEntity(myEntity);


        


        CloseableHttpResponse response      = null;


        InputStream inputStream

        = null;


        InputStreamReader inputStreamReader = null;


        BufferedReader bufferedReader       = null;


        try {


       

response = httpclient.execute(httpPost);


       

HttpEntity entity = response.getEntity();


if (entity!=null){


inputStream = entity.getContent();


inputStreamReader = new InputStreamReader(inputStream,WChatInfo.CHARSET);


bufferedReader = new BufferedReader(inputStreamReader);


String str = null;


while ((str = bufferedReader.readLine()) != null) {


reultBuffer.append(str);


}


}


} catch (ClientProtocolException e) {


e.printStackTrace();


} catch (IOException e) {


e.printStackTrace();


}finally{




httpclient.close();


response.close();


bufferedReader.close();


inputStreamReader.close();


inputStream.close();


inputStream = null;


}


     


        return reultBuffer.toString();


}


/**


* httpClient 请求企业支付到银行卡


* @param parms


* @return  


* @throws Exception


*/


public static String httpClientResultPANK(String xml) throws Exception{


StringBuffer reultBuffer = new StringBuffer();




SSLConnectionSocketFactory sslsf = ReadSSl.getInstance().readCustomSSL();




HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank");


        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();


        StringEntity myEntity = new org.apache.http.entity.StringEntity(xml, WChatInfo.CHARSET);


        myEntity.setContentType("text/xml;charset=UTF-8");


        myEntity.setContentEncoding(WChatInfo.CHARSET);


        httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");


        httpPost.setEntity(myEntity);


        


        CloseableHttpResponse response      = null;


        InputStream inputStream

        = null;


        InputStreamReader inputStreamReader = null;


        BufferedReader bufferedReader       = null;


        try {


       

response = httpclient.execute(httpPost);


       

HttpEntity entity = response.getEntity();


if (entity!=null){


inputStream = entity.getContent();


inputStreamReader = new InputStreamReader(inputStream, WChatInfo.CHARSET);


bufferedReader = new BufferedReader(inputStreamReader);


String str = null;


while ((str = bufferedReader.readLine()) != null) {


reultBuffer.append(str);


}


}


} catch (ClientProtocolException e) {


e.printStackTrace();


} catch (IOException e) {


e.printStackTrace();


}finally{




httpclient.close();


response.close();


bufferedReader.close();


inputStreamReader.close();


inputStream.close();


inputStream = null;


}


    


        return reultBuffer.toString();


}




}




/**


 * 读取证书


 * 


 *


 */


@SuppressWarnings("deprecation")


public class ReadSSl {


private static ReadSSl readSSL = null;




private ReadSSl(){




}




public static ReadSSl getInstance(){


if(readSSL == null){


readSSL = new ReadSSl();


}


return readSSL;


}


/**


*  读取 apiclient_cert.p12 证书


* @return


* @throws Exception


*/


public  SSLConnectionSocketFactory readCustomSSL() throws Exception{


    KeyStore keyStore  = KeyStore.getInstance("PKCS12");


        FileInputStream instream = new FileInputStream(new File(WChatInfo.CA_LICENSE));


        try {


            keyStore.load(instream, WChatInfo.MCH_ID.toCharArray());


        } finally {


            instream.close();


        }


        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WChatInfo.MCH_ID.toCharArray()).build();


        


        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null,


                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);


        return sslsf;


}




}




public class RSAEncrypt {  


 


    private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',  


            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  


  




 


    public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)  


            throws Exception {  


        try {  


            byte[] buffer = Base64.decode(publicKeyStr);  


            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  


            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);  


            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  


        } catch (NoSuchAlgorithmException e) {  


            throw new Exception("出错了");  


        } catch (InvalidKeySpecException e) {  


            throw new Exception("出错了");  


        } catch (NullPointerException e) {  


            throw new Exception("出错了");  


        }  


    }  


  






  


    /** 


     * 


     *  


     * @param publicKey 


     *           


     * @param plainTextData 


     *          


     * @return 


     * @throws Exception 


     *            


     */  


    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)  


            throws Exception {  


        if (publicKey == null) {  


            throw new Exception("");  


        }  


        Cipher cipher = null;  


        try {  


           


            cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");  


           


            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  


            byte[] output = cipher.doFinal(plainTextData);  


            return output;  


        } catch (NoSuchAlgorithmException e) {  


            throw new Exception("出错了");  


        } catch (NoSuchPaddingException e) {  


            e.printStackTrace();  


            return null;  


        } catch (InvalidKeyException e) {  


            throw new Exception("出错了");  


        } catch (IllegalBlockSizeException e) {  


            throw new Exception("出错了");  


        } catch (BadPaddingException e) {  


            throw new Exception("出错了");  


        }  


    }  


  


   






 4.获取的公钥需要转化后才能使用


 注明:因为上述获取的公钥是PKCS#1格式的,java可以直接使用的是PKCS#8格式的公钥,所以需要将PKCS#1格式的公钥转换为PKCS#8格式的公钥


 PKCS#1 转 PKCS#8


 linux下的转换命令:


 openssl rsa -RSAPublicKey_in -in <filename> -pubout


 注意:将转换后的公钥保存起来,因为后面需要用来加密收款方银行卡号和收款方用户名


 如:在.properties的文件中配置:publicKey="bhfuruynvoiudnfxnjwpqfnnfnfnjiy46488578937583892u4bbuffbf"


 


 


 5.企业支付到银行卡的http请求


   请求接口:https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank


   请求方式:post


   请求参数:mch_id,partner_trade_no(商户订单号,需保持唯一(只允许数字[0~9]或字母[A~Z]和[a~z],最短8位,最长32位),如:时间戳拼上几位随机数,保证唯一即可),


            nonce_str(随机字符串,不长于32位),sign(签名),enc_bank_no(收款方银行卡号,是配合公钥加密后的卡号),enc_true_name(收款方用户名,是配合公钥加密后的用户名)


bank_code(收款方开户行,就是具体银行对应的编号,具体在:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_4),


amount(付款金额(不含手续费的金额),单位为分),desc(付款说明,这个可传可不传)






public class TestWChatToBank {




/**


*测试企业支付到银行卡功能


* @param args


* @throws Exception 


*/


public static void main(String[] args) throws Exception {


// TODO Auto-generated method stub


String source ="李四";//银行卡开户名


String pank = "6220002340018125678";//银行卡号


//注意 这里的  publicKeyPKCS8  是上一步获取微信支付公钥后经openssl 转化成PKCS8格式的公钥


String publicKeyPKCS8 = "";//转换为PKCS8格式后的公钥


//获得RAS加密后的收款方用户名


String enc_true_name =GetRSA.getRSA(source,publicKeyPKCS8);//将收款方用户名配合公钥加密


//获得RAS加密后的收款方银行卡号


String enc_bank_no = GetRSA.getRSA(pank,publicKeyPKCS8);//将收款方银行卡号配合公钥加密


    String bank_code = "1003";//开户行对应的编号


    String amount = "100";//付款金额,这里是100分


    String desc ="测试";//付款说明


    String partner_trade_no = "2017112433233331";//商户订单号


  


    String nonce_str1 =  StringUtils1.getStrRandom(28);//获得随机字符串


    


    //获取签名


    SortedMap<Object,Object> parameters1 = new TreeMap<Object,Object>();


parameters1.put("mch_id", WChatInfo.MCH_ID);


parameters1.put("partner_trade_no", partner_trade_no);


parameters1.put("nonce_str", nonce_str1);


parameters1.put("enc_bank_no", enc_bank_no);


parameters1.put("enc_true_name", enc_true_name);


parameters1.put("bank_code", bank_code);


parameters1.put("amount", amount);


parameters1.put("desc", desc);


String sign1 = SignUtils.creatSign(WChatInfo.CHARSET, parameters1);


//请求企业付款


TreeMap<String, String> tmap1 = new TreeMap<String, String>();


tmap1.put("mch_id", WChatInfo.MCH_ID);


tmap1.put("partner_trade_no", partner_trade_no);


tmap1.put("nonce_str", nonce_str1);


tmap1.put("enc_bank_no", enc_bank_no);


tmap1.put("enc_true_name", enc_true_name);


tmap1.put("bank_code", bank_code);


tmap1.put("amount", amount);


tmap1.put("desc", desc);


tmap1.put("sign", sign1);


String xml2 = XMLUtils.getRequestXml(tmap1);//将请求参数转换为请求报文




String  xml3= HttpClientCustomSSL.httpClientResultPANK(xml2);//发送请求


System.out.println(xml3);






}




}




/**


 * rsa加密


 * 


 * */


public class GetRSA {  


 /**


  * @param publicKeyPKCS8  为pkcs8格式的公钥


  * */


   public static String getRSA(String str,String publicKeyPKCS8) throws Exception {  


       byte[] cipherData=RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(publicKeyPKCS8),str.getBytes());  


       String cipher=Base64.encode(cipherData);  


       return cipher;


         


   }  


}  




public class RSAEncrypt {  


 


    private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',  


            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  


  




 


    public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)  


            throws Exception {  


        try {  


            byte[] buffer = Base64.decode(publicKeyStr);  


            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  


            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);  


            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  


        } catch (NoSuchAlgorithmException e) {  


            throw new Exception("出错了");  


        } catch (InvalidKeySpecException e) {  


            throw new Exception("出错了");  


        } catch (NullPointerException e) {  


            throw new Exception("出错了");  


        }  


    }  


  


    /** 


     * 


     *  


     * @param publicKey 


     *           


     * @param plainTextData 


     *          


     * @return 


     * @throws Exception 


     *            


     */  


    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)  


            throws Exception {  


        if (publicKey == null) {  


            throw new Exception("");  


        }  


        Cipher cipher = null;  


        try {  


           


            cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");  


           


            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  


            byte[] output = cipher.doFinal(plainTextData);  


            return output;  


        } catch (NoSuchAlgorithmException e) {  


            throw new Exception("出错了");  


        } catch (NoSuchPaddingException e) {  


            e.printStackTrace();  


            return null;  


        } catch (InvalidKeyException e) {  


            throw new Exception("出错了");  


        } catch (IllegalBlockSizeException e) {  


            throw new Exception("出错了");  


        } catch (BadPaddingException e) {  


            throw new Exception("出错了");  


        }  


    }  


  


   






public final class Base64 {  


  


    static private final int     BASELENGTH           = 128;  


    static private final int     LOOKUPLENGTH         = 64;  


    static private final int     TWENTYFOURBITGROUP   = 24;  


    static private final int     EIGHTBIT             = 8;  


    static private final int     SIXTEENBIT           = 16;  


    static private final int     FOURBYTE             = 4;  


    static private final int     SIGN                 = -128;  


    static private final char    PAD                  = '=';  


    static private final boolean fDebug               = false;  


    static final private byte[]  base64Alphabet       = new byte[BASELENGTH];  


    static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];  


  


    static {  


        for (int i = 0; i < BASELENGTH; ++i) {  


            base64Alphabet[i] = -1;  


        }  


        for (int i = 'Z'; i >= 'A'; i--) {  


            base64Alphabet[i] = (byte) (i - 'A');  


        }  


        for (int i = 'z'; i >= 'a'; i--) {  


            base64Alphabet[i] = (byte) (i - 'a' + 26);  


        }  


  


        for (int i = '9'; i >= '0'; i--) {  


            base64Alphabet[i] = (byte) (i - '0' + 52);  


        }  


  


        base64Alphabet['+'] = 62;  


        base64Alphabet['/'] = 63;  


  


        for (int i = 0; i <= 25; i++) {  


            lookUpBase64Alphabet[i] = (char) ('A' + i);  


        }  


  


        for (int i = 26, j = 0; i <= 51; i++, j++) {  


            lookUpBase64Alphabet[i] = (char) ('a' + j);  


        }  


  


        for (int i = 52, j = 0; i <= 61; i++, j++) {  


            lookUpBase64Alphabet[i] = (char) ('0' + j);  


        }  


        lookUpBase64Alphabet[62] = (char) '+';  


        lookUpBase64Alphabet[63] = (char) '/';  


  


    }  


  


    private static boolean isWhiteSpace(char octect) {  


        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);  


    }  


  


    private static boolean isPad(char octect) {  


        return (octect == PAD);  


    }  


  


    private static boolean isData(char octect) {  


        return (octect < BASELENGTH && base64Alphabet[octect] != -1);  


    }  


  


    /** 


     * Encodes hex octects into Base64 


     * 


     * @param binaryData Array containing binaryData 


     * @return Encoded Base64 array 


     */  


    public static String encode(byte[] binaryData) {  


  


        if (binaryData == null) {  


            return null;  


        }  


  


        int lengthDataBits = binaryData.length * EIGHTBIT;  


        if (lengthDataBits == 0) {  


            return "";  


        }  


  


        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;  


        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;  


        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;  


        char encodedData[] = null;  


  


        encodedData = new char[numberQuartet * 4];  


  


        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;  


  


        int encodedIndex = 0;  


        int dataIndex = 0;  


        if (fDebug) {  


            System.out.println("number of triplets = " + numberTriplets);  


        }  


  


        for (int i = 0; i < numberTriplets; i++) {  


            b1 = binaryData[dataIndex++];  


            b2 = binaryData[dataIndex++];  


            b3 = binaryData[dataIndex++];  


  


            if (fDebug) {  


                System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);  


            }  


  


            l = (byte) (b2 & 0x0f);  


            k = (byte) (b1 & 0x03);  


  


            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  


            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);  


            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);  


  


            if (fDebug) {  


                System.out.println("val2 = " + val2);  


                System.out.println("k4   = " + (k << 4));  


                System.out.println("vak  = " + (val2 | (k << 4)));  


            }  


  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];  


        }  


  


        // form integral number of 6-bit groups  


        if (fewerThan24bits == EIGHTBIT) {  


            b1 = binaryData[dataIndex];  


            k = (byte) (b1 & 0x03);  


            if (fDebug) {  


                System.out.println("b1=" + b1);  


                System.out.println("b1<<2 = " + (b1 >> 2));  


            }  


            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];  


            encodedData[encodedIndex++] = PAD;  


            encodedData[encodedIndex++] = PAD;  


        } else if (fewerThan24bits == SIXTEENBIT) {  


            b1 = binaryData[dataIndex];  


            b2 = binaryData[dataIndex + 1];  


            l = (byte) (b2 & 0x0f);  


            k = (byte) (b1 & 0x03);  


  


            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  


            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);  


  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];  


            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];  


            encodedData[encodedIndex++] = PAD;  


        }  


  


        return new String(encodedData);  


    }  


  


    /** 


     * Decodes Base64 data into octects 


     * 


     * @param encoded string containing Base64 data 


     * @return Array containind decoded data. 


     */  


    public static byte[] decode(String encoded) {  


  


        if (encoded == null) {  


            return null;  


        }  


  


        char[] base64Data = encoded.toCharArray();  


        // remove white spaces  


        int len = removeWhiteSpace(base64Data);  


  


        if (len % FOURBYTE != 0) {  


            return null;//should be divisible by four  


        }  


  


        int numberQuadruple = (len / FOURBYTE);  


  


        if (numberQuadruple == 0) {  


            return new byte[0];  


        }  


  


        byte decodedData[] = null;  


        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;  


        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;  


  


        int i = 0;  


        int encodedIndex = 0;  


        int dataIndex = 0;  


        decodedData = new byte[(numberQuadruple) * 3];  


  


        for (; i < numberQuadruple - 1; i++) {  


  


            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))  


                || !isData((d3 = base64Data[dataIndex++]))  


                || !isData((d4 = base64Data[dataIndex++]))) {  


                return null;  


            }//if found "no data" just return null  


  


            b1 = base64Alphabet[d1];  


            b2 = base64Alphabet[d2];  


            b3 = base64Alphabet[d3];  


            b4 = base64Alphabet[d4];  


  


            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  


            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  


            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);  


        }  


  


        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {  


            return null;//if found "no data" just return null  


        }  


  


        b1 = base64Alphabet[d1];  


        b2 = base64Alphabet[d2];  


  


        d3 = base64Data[dataIndex++];  


        d4 = base64Data[dataIndex++];  


        if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters  


            if (isPad(d3) && isPad(d4)) {  


                if ((b2 & 0xf) != 0)//last 4 bits should be zero  


                {  


                    return null;  


                }  


                byte[] tmp = new byte[i * 3 + 1];  


                System.arraycopy(decodedData, 0, tmp, 0, i * 3);  


                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);  


                return tmp;  


            } else if (!isPad(d3) && isPad(d4)) {  


                b3 = base64Alphabet[d3];  


                if ((b3 & 0x3) != 0)//last 2 bits should be zero  


                {  


                    return null;  


                }  


                byte[] tmp = new byte[i * 3 + 2];  


                System.arraycopy(decodedData, 0, tmp, 0, i * 3);  


                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  


                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  


                return tmp;  


            } else {  


                return null;  


            }  


        } else { //No PAD e.g 3cQl  


            b3 = base64Alphabet[d3];  


            b4 = base64Alphabet[d4];  


            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  


            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  


            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);  


  


        }  


  


        return decodedData;  


    }  


  


    /** 


     * remove WhiteSpace from MIME containing encoded Base64 data. 


     * 


     * @param data  the byte array of base64 data (with WS) 


     * @return      the new length 


     */  


    private static int removeWhiteSpace(char[] data) {  


        if (data == null) {  


            return 0;  


        }  


  


        // count characters that's not whitespace  


        int newSize = 0;  


        int len = data.length;  


        for (int i = 0; i < len; i++) {  


            if (!isWhiteSpace(data[i])) {  


                data[newSize++] = data[i];  


            }  


        }  


        return newSize;  


    }