1. 程式人生 > >java服務端整合騰訊IM 生成usersig的方法

java服務端整合騰訊IM 生成usersig的方法

因為專案接入騰訊IM,需要在服務端生成sig簽名。廢話不多說,直接上碼。(文件中所涉及到的檔案和工具請在文章底部下載)

第一步 申請應用:

騰訊雲申請IM,建立一個雲通訊應用。生成以下資料:

1.SDKAPPID

2.公私鑰(public_key、private_key)

3.賬號管理員id

第二步 準備開發資料:

1.需要的jar包:  

bcpkix-jdk15on-152.jar

bcprov-jdk15on-152.jar

commons-codec-1.10.jar

gson-2.3.1.jar

json.jar

tls_sig_api.jar

2.使用openssl 將私鑰檔案(private_key)做如下的格式轉換(openssl在tls_sig_api-windows-64\tls_sig_api-windows-64\tools目錄下面)

cmd進入tls_sig_api-windows-64\tls_sig_api-windows-64\tools目錄執行下面命令 儲存好檔案

openssl pkcs8 -topk8 -in private_key -outform PEM -out p8_priv.pem -nocrypt

3.在專案中匯入上面的jar包

4.新建tls_sigature.java 

把tls_sigature類中main方法的privStr換成剛剛使用openssl轉換後的私鑰,pubStr換成你自己的應用生成public_key檔案內容。

同樣也要把SDKAPPID和identifier換成你自己的 然後執行main方法就可以生成usersig了! 

package com.tls.tls_sigature;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.nio.charset.Charset;

import java.security.Signature;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.Arrays;
import org.json.JSONObject;

import com.tls.base64_url.base64_url;

public class tls_sigature {
	public static class GenTLSSignatureResult
	{
		public String errMessage;
		public String urlSig;
		public int expireTime;
		public int initTime;
		public GenTLSSignatureResult()
		{
			errMessage = "";
			urlSig = "";
		}
	}

	public static class CheckTLSSignatureResult
	{
		public String errMessage;
		public boolean verifyResult;
		public int expireTime;
		public int initTime;
		public CheckTLSSignatureResult()
		{
			errMessage = "";
			verifyResult = false;
		}
	}

	public static void main(String[] args) {
		try{			
			//Use pemfile keys to test
		    String privStr = "-----BEGIN PRIVATE KEY-----\n" +
			"MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgiBPYMVTjspLfqoq46oZd\n" +
			"j9A0C8p7aK3Fi6/4zLugCkehRANCAATU49QhsAEVfIVJUmB6SpUC6BPaku1g/dzn\n" +
			"0Nl7iIY7W7g2FoANWnoF51eEUb6lcZ3gzfgg8VFGTpJriwHQWf5T\n" +
			"-----END PRIVATE KEY-----";
		    
			//change public pem string to public string
			String pubStr = "-----BEGIN PUBLIC KEY-----\n"+
			"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1OPUIbABFXyFSVJgekqVAugT2pLtYP3c\n"+
			"59DZe4iGO1u4NhaADVp6BedXhFG+pXGd4M34IPFRRk6Sa4sB0Fn+Uw==\n"+
			"-----END PUBLIC KEY-----";			

            // generate signature
            GenTLSSignatureResult result = GenTLSSignatureEx(1400000955, "xiaojun", privStr);
            if (0 == result.urlSig.length()) {
                System.out.println("GenTLSSignatureEx failed: " + result.errMessage);
                return;
            }
            
            System.out.println("---\ngenerate sig:\n" + result.urlSig + "\n---\n");
		    	
            // check signature
            CheckTLSSignatureResult checkResult = CheckTLSSignatureEx(result.urlSig, 1400000955, "xiaojun", pubStr);
            if(checkResult.verifyResult == false) {
                System.out.println("CheckTLSSignature failed: " + result.errMessage);
                return;
            }
            
            System.out.println("\n---\ncheck sig ok -- expire time " + checkResult.expireTime + " -- init time " + checkResult.initTime + "\n---\n");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * @brief 生成 tls 票據
	 * @param expire 有效期,單位是秒,推薦一個月
	 * @param strAppid3rd 填寫與 sdkAppid 一致字符串形式的值
	 * @param skdAppid 應用的 appid
	 * @param identifier 使用者 id
	 * @param accountType 建立應用後在配置頁面上展示的 acctype
	 * @param privStr 生成 tls 票據使用的私鑰內容
	 * @return 如果出錯,GenTLSSignatureResult 中的 urlSig為空,errMsg 為出錯資訊,成功返回有效的票據
	 * @throws IOException
	 */
	@Deprecated
	public static GenTLSSignatureResult GenTLSSignature(long expire, 
			String strAppid3rd, long skdAppid, 
			String identifier, long accountType, 
			String privStr ) throws IOException
	{

		GenTLSSignatureResult result = new GenTLSSignatureResult();
		
        Security.addProvider(new BouncyCastleProvider());
        Reader reader = new CharArrayReader(privStr.toCharArray());
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PEMParser parser = new PEMParser(reader);
        Object obj = parser.readObject();
        parser.close();
    	PrivateKey privKeyStruct = converter.getPrivateKey((PrivateKeyInfo) obj);
		
		//Create Json string and serialization String 
		String jsonString = "{" 
		+ "\"TLS.account_type\":\"" + accountType +"\","
		+"\"TLS.identifier\":\"" + identifier +"\","
		+"\"TLS.appid_at_3rd\":\"" + strAppid3rd +"\","
	    +"\"TLS.sdk_appid\":\"" + skdAppid +"\","
		+"\"TLS.expire_after\":\"" + expire +"\""
		+"}";
		//System.out.println("#jsonString : \n" + jsonString);
		
		String time = String.valueOf(System.currentTimeMillis()/1000);
		String SerialString = 
			"TLS.appid_at_3rd:" + strAppid3rd + "\n" +
			"TLS.account_type:" + accountType + "\n" +
			"TLS.identifier:" + identifier + "\n" + 
			"TLS.sdk_appid:" + skdAppid + "\n" + 
			"TLS.time:" + time + "\n" +
			"TLS.expire_after:" + expire +"\n";
	
		
		//System.out.println("#SerialString : \n" + SerialString);
		//System.out.println("#SerialString Hex: \n" + Hex.encodeHexString(SerialString.getBytes()));
		
		try{
			//Create Signature by SerialString
			Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
			signature.initSign(privKeyStruct);
			signature.update(SerialString.getBytes(Charset.forName("UTF-8")));
			byte[] signatureBytes = signature.sign();
			
			String sigTLS = Base64.encodeBase64String(signatureBytes);
			//System.out.println("#sigTLS : " + sigTLS);
			
			//Add TlsSig to jsonString
		    JSONObject jsonObject= new JSONObject(jsonString);
		    jsonObject.put("TLS.sig", (Object)sigTLS);
		    jsonObject.put("TLS.time", (Object)time);
		    jsonString = jsonObject.toString();
		    
		   // System.out.println("#jsonString : \n" + jsonString);
		    
		    //compression
		    Deflater compresser = new Deflater();
		    compresser.setInput(jsonString.getBytes(Charset.forName("UTF-8")));

		    compresser.finish();
		    byte [] compressBytes = new byte [512];
		    int compressBytesLength = compresser.deflate(compressBytes);
		    compresser.end();
		    //System.out.println("#compressBytes "+ compressBytesLength+": " + Hex.encodeHexString(Arrays.copyOfRange(compressBytes,0,compressBytesLength)));

		    //String userSig = Base64.encodeBase64URLSafeString(Arrays.copyOfRange(compressBytes,0,compressBytesLength));
		    String userSig = new String(base64_url.base64EncodeUrl(Arrays.copyOfRange(compressBytes,0,compressBytesLength)));
    
		    result.urlSig = userSig;
		    //System.out.println("urlSig: "+ userSig);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			result.errMessage = "generate usersig failed";
		}
		
		return result;
	}

	/**
	 * @brief 校驗 tls 票據
	 * @param urlSig 返回 tls 票據
	 * @param strAppid3rd 填寫與 sdkAppid 一致的字串形式的值
	 * @param skdAppid 應的 appid
	 * @param identifier 使用者 id
	 * @param accountType 建立應用後在配置頁面上展示的 acctype
	 * @param publicKey 用於校驗 tls 票據的公鑰內容,但是需要先將公鑰檔案轉換為 java 原生 api 使用的格式,下面是推薦的命令
	 *         openssl pkcs8 -topk8 -in ec_key.pem -outform PEM -out p8_priv.pem -nocrypt
	 * @return 如果出錯 CheckTLSSignatureResult 中的 verifyResult 為 false,錯誤資訊在 errMsg,校驗成功為 true
	 * @throws DataFormatException
	 */
	@Deprecated
	public static CheckTLSSignatureResult CheckTLSSignature( String urlSig,
			String strAppid3rd, long skdAppid, 
			String identifier, long accountType, 
			String publicKey ) throws DataFormatException
	{
		CheckTLSSignatureResult result = new CheckTLSSignatureResult();	
        Security.addProvider(new BouncyCastleProvider());
		
		//DeBaseUrl64 urlSig to json
		Base64 decoder = new Base64();

		//byte [] compressBytes = decoder.decode(urlSig.getBytes());
		byte [] compressBytes = base64_url.base64DecodeUrl(urlSig.getBytes(Charset.forName("UTF-8")));
		
		//System.out.println("#compressBytes Passing in[" + compressBytes.length + "] " + Hex.encodeHexString(compressBytes));
	
		//Decompression
		Inflater decompression =  new Inflater();
		decompression.setInput(compressBytes, 0, compressBytes.length);
		byte [] decompressBytes = new byte [1024];
		int decompressLength = decompression.inflate(decompressBytes);
		decompression.end();
		
		String jsonString = new String(Arrays.copyOfRange(decompressBytes, 0, decompressLength));
		
		//System.out.println("#Json String passing in : \n" + jsonString);
		
		//Get TLS.Sig from json
		JSONObject jsonObject= new JSONObject(jsonString);
		String sigTLS = jsonObject.getString("TLS.sig");
		
		//debase64 TLS.Sig to get serailString
		byte[] signatureBytes = decoder.decode(sigTLS.getBytes(Charset.forName("UTF-8")));
		
		try{
			
			String sigTime = jsonObject.getString("TLS.time");
			String sigExpire = jsonObject.getString("TLS.expire_after");
			
			//checkTime
			//System.out.println("#time check: "+ System.currentTimeMillis()/1000 + "-" 
					//+ Long.parseLong(sigTime) + "-" + Long.parseLong(sigExpire));
			if( System.currentTimeMillis()/1000 - Long.parseLong(sigTime) > Long.parseLong(sigExpire))
			{
				result.errMessage = new String("TLS sig is out of date ");
				System.out.println("Timeout");
				return result;
			}
			
			//Get Serial String from json
			String SerialString = 
				"TLS.appid_at_3rd:" + strAppid3rd + "\n" +
				"TLS.account_type:" + accountType + "\n" +
				"TLS.identifier:" + identifier + "\n" + 
				"TLS.sdk_appid:" + skdAppid + "\n" + 
				"TLS.time:" + sigTime + "\n" + 
				"TLS.expire_after:" + sigExpire + "\n";
		
			//System.out.println("#SerialString : \n" + SerialString);
		
	        Reader reader = new CharArrayReader(publicKey.toCharArray());
	        PEMParser  parser = new PEMParser(reader);
	        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
	        Object obj = parser.readObject();
	        parser.close();
	        PublicKey pubKeyStruct  = converter.getPublicKey((SubjectPublicKeyInfo) obj);

			Signature signature = Signature.getInstance("SHA256withECDSA","BC");
			signature.initVerify(pubKeyStruct);
			signature.update(SerialString.getBytes(Charset.forName("UTF-8")));
			boolean bool = signature.verify(signatureBytes);
			//System.out.println("#jdk ecdsa verify : " + bool);
			result.verifyResult = bool;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			result.errMessage = "Failed in checking sig";
		}
		
		return result;
	}

	/**
	 * @brief 生成 tls 票據,精簡引數列表,有效期預設為 180 天
	 * @param skdAppid 應用的 sdkappid
	 * @param identifier 使用者 id
	 * @param privStr 私鑰檔案內容
	 * @return
	 * @throws IOException
	 */
	public static GenTLSSignatureResult GenTLSSignatureEx(
			long skdAppid,
			String identifier,
			String privStr) throws IOException {
		return GenTLSSignatureEx(skdAppid, identifier, privStr, 3600*24*180);
	}

	/**
	 * @brief 生成 tls 票據,精簡引數列表
	 * @param skdAppid 應用的 sdkappid
	 * @param identifier 使用者 id
	 * @param privStr 私鑰檔案內容
	 * @param expire 有效期,以秒為單位,推薦時長一個月
	 * @return
	 * @throws IOException
	 */
	public static GenTLSSignatureResult GenTLSSignatureEx(
			long skdAppid,
			String identifier,
			String privStr,
			long expire) throws IOException {

		GenTLSSignatureResult result = new GenTLSSignatureResult();
		
        Security.addProvider(new BouncyCastleProvider());
        Reader reader = new CharArrayReader(privStr.toCharArray());
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PEMParser parser = new PEMParser(reader);
        Object obj = parser.readObject();
        parser.close();
    	PrivateKey privKeyStruct = converter.getPrivateKey((PrivateKeyInfo) obj);
		
		String jsonString = "{" 
		+ "\"TLS.account_type\":\"" + 0 +"\","
		+"\"TLS.identifier\":\"" + identifier +"\","
		+"\"TLS.appid_at_3rd\":\"" + 0 +"\","
	    +"\"TLS.sdk_appid\":\"" + skdAppid +"\","
		+"\"TLS.expire_after\":\"" + expire +"\","
        +"\"TLS.version\": \"201512300000\""
		+"}";
		
		String time = String.valueOf(System.currentTimeMillis()/1000);
		String SerialString = 
			"TLS.appid_at_3rd:" + 0 + "\n" +
			"TLS.account_type:" + 0 + "\n" +
			"TLS.identifier:" + identifier + "\n" + 
			"TLS.sdk_appid:" + skdAppid + "\n" + 
			"TLS.time:" + time + "\n" +
			"TLS.expire_after:" + expire +"\n";
		
		try {
			//Create Signature by SerialString
			Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
			signature.initSign(privKeyStruct);
			signature.update(SerialString.getBytes(Charset.forName("UTF-8")));
			byte[] signatureBytes = signature.sign();
			
			String sigTLS = Base64.encodeBase64String(signatureBytes);
			
			//Add TlsSig to jsonString
		    JSONObject jsonObject= new JSONObject(jsonString);
		    jsonObject.put("TLS.sig", (Object)sigTLS);
		    jsonObject.put("TLS.time", (Object)time);
		    jsonString = jsonObject.toString();
		    
		    //compression
		    Deflater compresser = new Deflater();
		    compresser.setInput(jsonString.getBytes(Charset.forName("UTF-8")));

		    compresser.finish();
		    byte [] compressBytes = new byte [512];
		    int compressBytesLength = compresser.deflate(compressBytes);
		    compresser.end();
		    String userSig = new String(base64_url.base64EncodeUrl(Arrays.copyOfRange(compressBytes,0,compressBytesLength)));
    
		    result.urlSig = userSig;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			result.errMessage = "generate usersig failed";
		}
		
		return result;
	}
	
	public static CheckTLSSignatureResult CheckTLSSignatureEx(
			String urlSig,
			long sdkAppid, 
			String identifier, 
			String publicKey ) throws DataFormatException {

		CheckTLSSignatureResult result = new CheckTLSSignatureResult();	
        Security.addProvider(new BouncyCastleProvider());
		
		//DeBaseUrl64 urlSig to json
		Base64 decoder = new Base64();

		byte [] compressBytes = base64_url.base64DecodeUrl(urlSig.getBytes(Charset.forName("UTF-8")));
		
		//Decompression
		Inflater decompression =  new Inflater();
		decompression.setInput(compressBytes, 0, compressBytes.length);
		byte [] decompressBytes = new byte [1024];
		int decompressLength = decompression.inflate(decompressBytes);
		decompression.end();
		
		String jsonString = new String(Arrays.copyOfRange(decompressBytes, 0, decompressLength));
		
		//Get TLS.Sig from json
		JSONObject jsonObject= new JSONObject(jsonString);
		String sigTLS = jsonObject.getString("TLS.sig");
		
		//debase64 TLS.Sig to get serailString
		byte[] signatureBytes = decoder.decode(sigTLS.getBytes(Charset.forName("UTF-8")));
		
		try {
			String strSdkAppid = jsonObject.getString("TLS.sdk_appid");
			String sigTime = jsonObject.getString("TLS.time");
			String sigExpire = jsonObject.getString("TLS.expire_after");
			
			if (Integer.parseInt(strSdkAppid) != sdkAppid)
			{
				result.errMessage = new String(	"sdkappid "
						+ strSdkAppid
						+ " in tls sig not equal sdkappid "
						+ sdkAppid
						+ " in request");
				return result;
			}

			if ( System.currentTimeMillis()/1000 - Long.parseLong(sigTime) > Long.parseLong(sigExpire)) {
				result.errMessage = new String("TLS sig is out of date");
				return result;
			}
			
			//Get Serial String from json
			String SerialString = 
				"TLS.appid_at_3rd:" + 0 + "\n" +
				"TLS.account_type:" + 0 + "\n" +
				"TLS.identifier:" + identifier + "\n" + 
				"TLS.sdk_appid:" + sdkAppid + "\n" + 
				"TLS.time:" + sigTime + "\n" + 
				"TLS.expire_after:" + sigExpire + "\n";
		
	        Reader reader = new CharArrayReader(publicKey.toCharArray());
	        PEMParser  parser = new PEMParser(reader);
	        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
	        Object obj = parser.readObject();
	        parser.close();
	        PublicKey pubKeyStruct  = converter.getPublicKey((SubjectPublicKeyInfo) obj);

			Signature signature = Signature.getInstance("SHA256withECDSA","BC");
			signature.initVerify(pubKeyStruct);
			signature.update(SerialString.getBytes(Charset.forName("UTF-8")));
			boolean bool = signature.verify(signatureBytes);
            result.expireTime = Integer.parseInt(sigExpire);
            result.initTime = Integer.parseInt(sigTime);
			result.verifyResult = bool;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			result.errMessage = "Failed in checking sig";
		}
		
		return result;
	}

}
base64_url.java

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.util.Arrays;

public class base64_url {
	static  byte base64_table_url[] =
    { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '-', '\0'};

	static  byte base64_pad_url = '_';

	static  short base64_reverse_table_url[] = {
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 63, -1, -1,
	    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
	    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
	    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
	    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
	    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
	};
	
	public static int unsignedToBytes(int b)
	{
		return b & 0xFF;
	}

	//int base64_encode_url(const unsigned char *in_str, int length, char *out_str,int *ret_length)
	public static byte [] base64EncodeUrl(byte [] in_str)
	{
		byte [] out_str = new byte [1024] ;

	    int out_current = 0;
	    int current = 0;
	    int length = in_str.length;

	    while (length > 2) { /* keep going until we have less than 24 bits */
	    	 
	    	out_str[out_current++] = base64_table_url[unsignedToBytes((unsignedToBytes(in_str[current]) >>> 2))];
	    	out_str[out_current++] = base64_table_url[unsignedToBytes(unsignedToBytes(unsignedToBytes(in_str[current]) & 0x03) << 4) + unsignedToBytes((unsignedToBytes(in_str[current+1]) >>> 4))];
	    	out_str[out_current++] = base64_table_url[(unsignedToBytes((unsignedToBytes(in_str[current+1]) & 0x0f)) << 2) + unsignedToBytes((unsignedToBytes(in_str[current+2]) >>> 6))];
	    	out_str[out_current++] = base64_table_url[unsignedToBytes((unsignedToBytes(in_str[current+2]) & 0x3f))];
	        current += 3;
	        length -= 3; /* we just handle 3 octets of data */
	    }

	    /* now deal with the tail end of things */
	    if (length != 0) {
	    	out_str[out_current++] = base64_table_url[unsignedToBytes(in_str[current]) >>> 2];
	        if (length > 1) {
	        	out_str[out_current++] = base64_table_url[unsignedToBytes((unsignedToBytes(in_str[current]) & 0x03) << 4) + unsignedToBytes(unsignedToBytes(in_str[current+1]) >>> 4)];
	        	out_str[out_current++] = base64_table_url[unsignedToBytes((unsignedToBytes(in_str[current + 1]) & 0x0f) << 2)];
	        	out_str[out_current++] = base64_pad_url;
	        } else {
	        	out_str[out_current++] = base64_table_url[unsignedToBytes((unsignedToBytes(in_str[current]) & 0x03) << 4)];
	        	out_str[out_current++] = base64_pad_url;
	        	out_str[out_current++] = base64_pad_url;
	        }
	    }
	    
        //System.out.println("length in base64EncodeUrl: " + out_current );
	    byte [] out_bytes = new String(out_str).getBytes(); 
	    return Arrays.copyOfRange(out_bytes, 0, out_current);
	}

	//int base64_decode_url(const unsigned char *in_str, int length, char *out_str, int *ret_length)
	public static byte [] base64DecodeUrl(byte [] in_str)
	{
	//        const unsigned char *current = in_str;
	        int ch, i = 0, j = 0, k;
	        
	        int current  = 0;
	        int result = 0;
	        byte [] out_str = new byte [1024] ;
			int length = in_str.length;
	        /* this sucks for threaded environments */

	        /* run through the whole string, converting as we go */
	        //while ((ch = in_str[current++]) != '\0' && length-- > 0) {
			ch = in_str[0];
			while(length-- > 0){
					ch = in_str[current++];
	                if (ch == base64_pad_url) break;
	                /* When Base64 gets POSTed, all pluses are interpreted as spaces.
	                   This line changes them back.  It's not exactly the Base64 spec,
	                   but it is completely compatible with it (the spec says that
	                   spaces are invalid).  This will also save many people considerable
	                   headache.  - Turadg Aleahmad <[email protected]>
	            */
	                if (ch == ' ') ch = '*'; //never using '+'

	                ch = base64_reverse_table_url[ch];
	                if (ch < 0) continue;

	                switch(i % 4) {
	                case 0:
	                	out_str[j] = (byte) unsignedToBytes( unsignedToBytes(ch) << 2);
	                    break;
	                case 1:
	                	out_str[j++] |= (byte) unsignedToBytes(unsignedToBytes(ch) >>> 4);
	                	out_str[j] = (byte) unsignedToBytes(unsignedToBytes(unsignedToBytes(ch) & 0x0f) << 4);
	                    break;
	                case 2:
	                	out_str[j++] |= (byte) unsignedToBytes(unsignedToBytes(ch) >>> 2);
	                	out_str[j] = (byte) unsignedToBytes(unsignedToBytes(unsignedToBytes(ch) & 0x03) << 6);
	                    break;
	                case 3:
	                	out_str[j++] |= (byte) unsignedToBytes(ch);
	                    break;
	                }
	                i++;
	        }
	        k = j;
	        /* mop things up if we ended on a boundary */
	        if (ch == base64_pad_url) { 	
	                switch(i % 4) {
	                case 0:
	                case 1:
	                        byte [] error =  new byte [1];
	                        error[0] = '\0';
	                        return error;
	                case 2:
	                    k++;
	                case 3:
	                	out_str[k++] = 0;
	                }
	        }
		    return Arrays.copyOfRange(out_str, 0, j);
	}
	public static void main(String[] args) throws DecoderException {
		
		//String hexString = "5095";
		String hexString = "789c6d8d4d4f83401884ff0b578c5dba0bbb98782015b1a1f8059a7222743fc8da96aecbdbdad6f8dfa5046fce6de6c9cc7c3bc522bfeec4baaa8dd1c2b9713c822e0a7ddfb91aa03c1a6d65552b90b6e794d2a0e7231c5a550d15b6ff96416fe590e38051c2281d732d640b5ae96172ea051c29be524c62e463e57382e854a08020a578c8febe38dfed5ba8e0642e9b98e21174bae97d16bfcde633299e0f49c81f27a26490b97665d7675dd0fdc35df1de994d23bc4301db349fbb918ea3e36b509878f7956d84dbb44b4ed23287b454f7119c12fea4968b64927d7c962179b9757e7e01ed1059d9";
		
		byte [] test = Hex.decodeHex(hexString.toCharArray());
		byte [] compressBytes = base64EncodeUrl(test);
		System.out.println("compress : " + new String(compressBytes));
		byte [] uncompressBytes = base64DecodeUrl(compressBytes);
		System.out.println("uncompress: " + Hex.encodeHexString(uncompressBytes));
	}
}

下載