java官方demo企业微信会话内容存档调用DecryptData返回中文出现乱码,请问如何解决?
以下的调用的代码 public static void main(String[] args) throws Exception {
// RSA rsa = SecureUtil.rsa();
// String privateKeyBase64 = rsa.getPrivateKeyBase64();
// String publicKeyBase64 = rsa.getPublicKeyBase64();
// System.out.println(publicKeyBase64);
// System.out.println("------------------------------");
// System.out.println(privateKeyBase64);
// System.out.println(RSA_PRIVATE);
// System.out.println("---------------------");
// System.out.println(RSA_PUBLIC);
test();
}
public static Result test() throws Exception {
//seq 表示该企业存档消息序号,该序号单调递增,拉取序号建议设置为上次拉取返回结果中最大序号。首次拉取时seq传0,sdk会返回有效期内最早的消息。
//limit 表示本次拉取的最大消息条数,取值范围为1~1000
//proxy与passwd为代理参数,如果运行sdk的环境不能直接访问外网,需要配置代理参数。sdk访问的域名是"https://qyapi.weixin.qq.com"。
//建议先通过curl访问"https://qyapi.weixin.qq.com",验证代理配置正确后,再传入sdk。
//timeout 为拉取会话存档的超时时间,单位为秒,建议超时时间设置为5s。
//sdkfileid 媒体文件id,从解密后的会话存档中得到
//savefile 媒体文件保存路径
//encrypt_key 拉取会话存档返回的encrypt_random_key,使用配置在企业微信管理台的rsa公钥对应的私钥解密后得到encrypt_key。
//encrypt_chat_msg 拉取会话存档返回的encrypt_chat_msg
String[] args = new String[6];
args[0] = "1";
args[1] = "0";
args[2] = "1000";
args[3] = "";
args[4] = "";
args[5] = "5"; //过期时间
if (args.length < 2) {
System.out.println("./sdktools 1(chatmsg) 2(mediadata) 3(decryptdata)\n");
System.out.println("./sdktools 1 seq limit proxy passwd timeout\n");
System.out.println("./sdktools 2 fileid proxy passwd timeout savefile\n");
System.out.println("./sdktools 3 encrypt_key encrypt_chat_msg\n");
return null;
}
long ret = 0;
//使用sdk前需要初始化,初始化成功后的sdk可以一直使用。
//如需并发调用sdk,建议每个线程持有一个sdk实例。
//初始化时请填入自己企业的corpid与secrectkey。
long sdk = Finance.NewSdk();
ret = Finance.Init(sdk, "ww3955317892b950b7", "SI1E-fF_TiSvSQSVjdr7qbhxSY1d9kF6MoMcLBtSVsw");
if(ret != 0){
Finance.DestroySdk(sdk);
System.out.println("init sdk err ret " + ret);
return null;
}
if (args[0].equals("1")) {
//拉取会话存档
int seq = Integer.parseInt(args[1]);
int limit = Integer.parseInt(args[2]);
String proxy = args[3];
String passwd = args[4];
int timeout = Integer.parseInt(args[5]);
//每次使用GetChatData拉取存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
long slice = Finance.NewSlice();
ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice);
if (ret != 0) {
System.out.println("getchatdata ret " + ret);
Finance.FreeSlice(slice);
return null;
}
System.out.println("getchatdata :" + Finance.GetContentFromSlice(slice));
JSONObject jsonObject = JSONUtil.parseObj(Finance.GetContentFromSlice(slice));
Object chatdata = jsonObject.get("chatdata");
JSONArray jsonArray = JSONUtil.parseArray(chatdata);
for(int i=0;i<jsonArray.size();i++){
JSONObject chatDataObj = JSONUtil.parseObj(jsonArray.get(i));
if("4".equals(chatDataObj.get("publickey_ver").toString())){
String encrypt_random_key = chatDataObj.get("encrypt_random_key").toString();
String encrypt_chat_msg = chatDataObj.get("encrypt_chat_msg").toString();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(RSA_PRIVATE));//getPrivateKey()返回的privateKey
byte[] randomkeybyte = Base64.getDecoder().decode(encrypt_random_key );
byte[] finalrandomkeybyte = cipher.doFinal(randomkeybyte);
String finalrandomkey = new String(finalrandomkeybyte);
long msg = Finance.NewSlice();
ret = Finance.DecryptData(sdk, finalrandomkey, encrypt_chat_msg, msg);
if (ret != 0) {
System.out.println("getchatdata ret " + ret);
Finance.FreeSlice(msg);
return null;
}
System.out.println("decrypt ret:" + ret + " msg:" + Finance.GetContentFromSlice(msg));
Finance.FreeSlice(msg);
}
}
Finance.FreeSlice(slice);
}
else if (args[0].equals("2")) {
//拉取媒体文件
String sdkfileid = args[1];
String proxy = args[2];
String passwd = args[3];
int timeout = Integer.parseInt(args[4]);
String savefile = args[5];
//媒体文件每次拉取的最大size为512k,因此超过512k的文件需要分片拉取。若该文件未拉取完整,sdk的IsMediaDataFinish接口会返回0,同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf。
//indexbuf一般格式如右侧所示,”Range:bytes=524288-1048575“,表示这次拉取的是从524288到1048575的分片。单个文件首次拉取填写的indexbuf为空字符串,拉取后续分片时直接填入上次返回的indexbuf即可。
String indexbuf = "";
while(true){
//每次使用GetMediaData拉取存档前需要调用NewMediaData获取一个media_data,在使用完media_data中数据后,还需要调用FreeMediaData释放。
long media_data = Finance.NewMediaData();
ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, media_data);
if(ret!=0){
System.out.println("getmediadata ret:" + ret);
Finance.FreeMediaData(media_data);
return null;
}
System.out.printf("getmediadata outindex len:%d, data_len:%d, is_finis:%d\n",Finance.GetIndexLen(media_data),Finance.GetDataLen(media_data), Finance.IsMediaDataFinish(media_data));
try {
//大于512k的文件会分片拉取,此处需要使用追加写,避免后面的分片覆盖之前的数据。
FileOutputStream outputStream = new FileOutputStream(new File(savefile), true);
outputStream.write(Finance.GetData(media_data));
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
if(Finance.IsMediaDataFinish(media_data) == 1)
{
//已经拉取完成最后一个分片
Finance.FreeMediaData(media_data);
break;
}
else
{
//获取下次拉取需要使用的indexbuf
indexbuf = Finance.GetOutIndexBuf(media_data);
Finance.FreeMediaData(media_data);
}
}
}
else if (args[0].equals("3")) {
//解密会话存档内容
//sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。
//此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。
String encrypt_key = "";
String encrypt_chat_msg = args[2];
//每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
long msg = Finance.NewSlice();
ret = Finance.DecryptData(sdk, encrypt_key, encrypt_chat_msg, msg);
if (ret != 0) {
System.out.println("getchatdata ret " + ret);
Finance.FreeSlice(msg);
return null;
}
System.out.println("decrypt ret:" + ret + " msg:" + Finance.GetContentFromSlice(msg));
Finance.FreeSlice(msg);
}
else {
System.out.println("wrong args " + args[0]);
}
Finance.DestroySdk(sdk);
return null;
}
//用此方法先获取秘钥
public static PrivateKey getPrivateKey(String privKeyPEM) throws Exception{
String privKeyPEMnew = privKeyPEM.replaceAll("\\n", "").replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "");
byte[] bytes = java.util.Base64.getDecoder().decode(privKeyPEMnew);
DerInputStream derReader = new DerInputStream(bytes);
DerValue[] seq = derReader.getSequence(0);
BigInteger modulus = seq[1].getBigInteger();
BigInteger publicExp = seq[2].getBigInteger();
BigInteger privateExp = seq[3].getBigInteger();
BigInteger prime1 = seq[4].getBigInteger();
BigInteger prime2 = seq[5].getBigInteger();
BigInteger exp1 = seq[6].getBigInteger();
BigInteger exp2 = seq[7].getBigInteger();
BigInteger crtCoef = seq[8].getBigInteger();
RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}