文档说明
业务约定
三方应用接入,只能使 用阿里提供的账号体系进行登录和授权,不能提供独立账号注册功能。
通信约定
支付服务端支持两种通信模式,即http(https)模式和TOP模式。
Https通信方式:适合于支付成功后的数娱服务端回调 使用https通信方式采用RSA公私钥加解密。该方式cp需要首先在数娱TV开放平台 (http://open.aliplay.com/)填写开发者的RSA公钥信息。 数娱使用CP填写的公钥进行加签,CP 的服务端接到回调后,使用私钥进行解签;回调的原始内容为json格式,具体字段定义参照网络支付接口-服务端支付成功后回调通知章节。 根据原始内容json串以及RSA公钥加密后的内容encryptedData会在http参数的data字段中供CP利用 RSA私钥解密后使用
TOP通信方式:适合于CP主动调用支付服务的场景(如查询订单状态等) 通过TOP通信方式,该方式CP需使用数娱TV开放平台(http://open.aliplay.com/)入住时颁发的 appkey和appsecret(该信息可以在阿里TV开放平台应用管理页面中查看), TOP接口的调用请参 考//open.taobao.com/doc2/detail.htm? spm=a219a.7629140.0.0.jlQptD&treeId=49&articleId=101617&docType=1
安全规范
为了防止双方约定的接口(服务端 )被滥用带来的不必要的安全风险,接入的合作方需要符合以下要求做好安全控制。 如有疑问,可加入旺旺群621730614 咨询。
1. 接口安全规范
1)接口以HTTP方式开放。
2)设计接口需要有身份认证,对来源授权,只允许授权的IP访问.
3)所有的接口调用都需要有日志记录 密钥的传递及保存 双方约定的密钥,不应该大范围邮件传递,应以开发人员人对 人传递。密钥需要妥善保存,避免泄露密钥引起的安全隐患。
2 密钥及appsecret的传递及保存
接入合作方所持有的敏感信息,不应该大范围邮件传递,应以开发人员人对人传递。私钥和appsecret需要妥善保存,避免泄露私钥引起的安全隐患。
技术示例
1. RSA秘钥生成方式
RSA是一种可用于进行签名的非对称算法,即签名密钥(私钥)与验签名密钥( 公钥)是不一样的,私钥用于签名,公钥用于验签名。使用这种算法签名在起到防数据篡改功能的 同时,还可以起到防抵赖的作用,因为私钥只有签名者知道。 可以使用Openssl RSA密钥生成工具 ,生成一套RSA公私钥。
RSA密钥生成命令:
生成 RSA私钥
openssl genrsa -out rsa_private_key.pem 1024
生成 RSA公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
将RSA私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
该工具生成的密钥文件,里面有一些注释和回车换行,需要将其去掉后组成一串字符!
2. RSA签名(sign)算法示例
Java参考代码
/**
* RSA签名算法
* @param privateKey
* @param content
* @param charset
* @return
* @throws Exception
*/
public static String sign(String privateKey, String content, String charset) throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decodeBase64(privateKey) );
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset) );
byte[] signed = signature.sign();
return Base64.encodeBase64String(signed);
}
PHP参考代码
$privkey = file_get_contents("rsa_private_key.pem"); //
无需转PKCS8
$res = openssl_get_privatekey($privkey);
openssl_sign($data, $sign, $res);
$sign = base64_encode($sign);
3. 服务端notify解密demo(java版)
package testRsa;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
/**
*
* @author zhiyong.xiongzy
*
*/
public class testRSA {
private static String prikey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMhDP5oVLHPJpM0QDuAGPupAkF4N3bMOD252BIYncKd8ppYJP0sA1wxnJxrVJN6UOzgK2qEReHUCzda5Hj+GaR8dmYz3v4UMozNeXhx7iqI7EK4Myp/qjCV2ROgh2LaL1ycugacTVx6dSfFvIOcczyhs8D4BUiJlSMsTWPVCSKsPAgMBAAECgYEAkL5KUgvLvUSZIL3ignkBMD7KGbDb9HbNIIGcc3o+KlAl93tni8ZnqEdGNFap91YcFz2BF7mQ3sHQFMpn2nJDtzj0tPsCKtNLHmpOi0ctAxedhzip+rOT6obNK+POL6czMWGJOaW8zLefxftgZWkT+eZactn507xc+GiwNsodAMECQQD4OjjnMhQWaSv8kHI27pH92PTv4zFb1msB0H65Im2zQ+8JrlqEH/7AqqMIxkPjIMC/vJLpkZG4TYMCYXjd4rx7AkEAzoiLGwUsXDApbDJJxxgYV6y50H/oJm6ooIOHoCwrluJhlOD81oUQyrLGfgNL95v4avvuQezZ4kmkeWDPvQ35fQJACBM8zqieZqw9NhYs4QSZ0zw/m540eNxc1s5FkRhBoVdQa2w0nZ+81d+3Ng3dH4JtQs+Lp/WIXAqJfIZXPECoCQJAW8QBgrTuu9tOXFuPul1zW2lMel6KiKD8Xa1zUnCtwXG+h8bbsHkZN+btGMpgM5libC6Z80LIoKm14ZRpWQffhQJBAJyxWEnzZA9dvqEhj6I/BTPJgvzc/boGzZ2lKQlN8j57MDkZHryoWtoKjB3Hp5dvTasweI6WHtIm313TSLuoXrg=";
public static void main(String[] args) {
String content = "c/BOhNHjhvCXvOenIyNqmr0FI1M3cYt/BR/WEoMgoi37ZFvKe418xOlRU4AN/QyvY2H7g2osL9oLmArsw35jk43reMFUyemTLnZ4Xw/DXT5xxPzHy4NWLt2/K0mqA2e5PiShf8RX9EdLnoIYZPXKe3Ldnw0ha3RZtP4X2tBsHqU=";
String jsonStr;
try {
//解密
jsonStr = decrypt(content, prikey, "UTF-8");
System.out.println(jsonStr);
//sign签名
System.out.println(sign(prikey, content, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* RSA签名算法
* @param privateKey
* @param content
* @param charset
* @return
* @throws Exception
*/
public static String sign(String privateKey, String content, String charset) throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decodeBase64(privateKey) );
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset) );
byte[] signed = signature.sign();
return Base64.encodeBase64String(signed);
}
public static String decrypt(String content, String private_key, String input_charset) throws Exception {
PrivateKey prikey = getPrivateKey(private_key);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, prikey);
InputStream ins = new ByteArrayInputStream(Base64.decodeBase64(content.getBytes()));
ByteArrayOutputStream writer = new ByteArrayOutputStream();
//rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
byte[] buf = new byte[128];
int bufl;
while ((bufl = ins.read(buf)) != -1) {
byte[] block = null;
if (buf.length == bufl) {
block = buf;
} else {
block = new byte[bufl];
for (int i = 0; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return new String(writer.toByteArray(), input_charset);
}
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = Base64.decodeBase64(key.getBytes());
//使用PKCS8
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return privateKey;
}
}
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
4. 服务端notify解密demo(php版)
<?php
$privkey=<<<EOT
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN/dCMqrU4GCvJ1s
QwPxvCnYSsXsm0+wdIzPBajdRiI9rvgtxRDq10yHGwXs+RNOGxaglj0F+9kRQ7l5
BEkN/HgPg90uWT6bNp5Qf4K3qJWfY6FmWoNDKYyIYjDacAVheAC/Idg/0nKgTUKH
sowx8iXHnKBB3o7B7XGoKCjFKc2PAgMBAAECgYEAjIVAqYdVyav5HZABmQ46oMGm
Xgshiqom3uRslw0eowu5Mwv38aCYOO9t5RBVYOrcUh3HcNK6vgz6SAhQylK/MKk8
hynSBnawh5/XZUUI7Zqw5NFoLIHgdKxcNzGhp5a6eTGOyPVXBi9/+PczeD5Enf2n
2RSCJV2yyAzxAzdM+DECQQD4eVHsYzkkmMFaPnJPWcGuLpl7hz1Fte5n83SiZhY/
6WJsC0FpKiCmpxrGhl2yM3gp0kS4b7/uuulIEQyPOAWdAkEA5qTiHZL/+GJOtxwU
kvvVplEmOKGHEcUSoLgxnBYS35S3qgxH4X989coyHV6EMNUXd5hO1vz3RnIVRvrx
sYsuGwJAcV9x2OlBNoiYmKOrprcun1pV375KX9duS3ITQtJPzqOfq+rK0sBNG51d
oz3F3LyNVI/DmWAr9DLGpIJa97I5JQJBALcqTmAKM7m/6J9Gb5hi4sMYQvBKZwfX
p/l3Df7VENv6MPmckyEjq8tObgog234kXGSf0kytzHpnczpRY8wJqe0CQCNv7Th8
jnlWQ21UVBL1Lr3KcMM/0RJ0hiVGH46Gp93h9c2zsAgHQ01HLi1BeRcM1tZZNPIh
GqEuuIa/iXjzNNc=
-----END PRIVATE KEY-----
EOT;
$res = openssl_get_privatekey($privkey);
//$content = "ycoYI7SXtj9GWHHNS27jeF18x7B0JVFxyb0+X/k4fjHpe7Jvwk7TGdT5VF+NWjBKpPVfyv5NRUYMNrHsHSeQgd4AWO6y3e5HWGmhCa92YdAzriSqoU2fAud4zJQtu1lKQP+iM5sC21GhSHlhm+2q443kKjuUX2Fl6wv4+H2onXBmbw2KHbz+knQW9AhjVoamYhy2X0XoAK6KtcQk7frk9ASqgf8iob0kteFp9HN/86+QFLUiH7BQm+Dh3tkDTBzIm4huCN4+bi71FLYLXLUYVWxcSC24S16Z11ihm771dFa+4w2taeAlhOEZHcE1w8uBXZPMlxlkT66OhvQXZRf88g==";
$content = $_POST['data'];
$content = base64_decode($content);
$i = 0;
$result = "";
while($head = substr($content, $i, 128)) {
$i += 128;
openssl_private_decrypt($head,$newsource,$res);
$result .= $newsource;
}
$result = json_decode($result, true);
var_dump($result);
SDK接入方法
1 在eclipse中导入demo,能看到2个工程:
1)AlitvSDKLib包含了SDK用到的lib和res
2)AlitvSDKDemo引用上述Lib工程
2 按照以下截图配置,把SDK引入您的工程
1) 在项目属性中配置
2) 在Java Build Path中配置
3)配置manifest可合并
在您的工程根目录中的project.properties里加入一行代码: manifestmerger.enabled=true