企业通过微信支付到个人银行卡的开发过程

由于前段时间开发需要,要实现企业通过微信支付到个人银行卡的功能,现在整理一下,里面的极大部分代码是一位大神写好的,然后自己在基础上列出了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;  
    }  



 
 
 
展开阅读全文

没有更多推荐了,返回首页