小程序冻结

代码示例

字节数组转换为16进制字符串示例

代码参考(C#):

public static string HexString(byte[] baSrc)
{
    if (baSrc == null)
    {
        return "";
    }

    int nByteNum = baSrc.Length;
    StringBuilder sbResult = new StringBuilder(nByteNum * 2);

    for (int i = 0; i < nByteNum; i++)
    {
        char chHex;
        
        byte btHigh = (byte)((baSrc[i] & 0xF0) >> 4);
        if (btHigh < 10)
        {
            chHex = (char)('0' + btHigh);
        }
        else
        {
            chHex = (char)('A' + (btHigh - 10));
        }
        sbResult.Append(chHex);

        byte btLow = (byte)(baSrc[i] & 0x0F);
        if (btLow < 10)
        {
            chHex = (char)('0' + btLow);
        }
        else
        {
            chHex = (char)('A' + (btLow - 10));
        }
        sbResult.Append(chHex);
    }

    return sbResult.ToString();
}


商户支付密钥签名示例

代码参考(C#):

// 假设已排序的待签名字符串为:strToSign
//拼接支付密钥
strToSign+= "&" + sMerchantKey;
//SHA-256签名
byte[]  baSrc  = Encoding.GetEncoding(“UTF-8”).GetBytes(strToSign.ToString());
SHA256 sha = new SHA256CryptoServiceProvider();
byte[]  baResult = sha.ComputeHash(baSrc);
//转为16进制字符串
string sign = HexString(baResult);

代码参考java版:

//假设已排序字符串为strToSign
//添加商户密钥
strToSign.append(“&”).append(sMerchantKey);
// 创建加密对象
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
// 传入要加密的字符串,按指定的字符集将字符串转换为字节流
messageDigest.update(strToSign.toString().getBytes("UTF-8"));
byte byteBuffer[] = messageDigest.digest();
// 將 byte数组转换为16进制string
String sign = HexString.toString();

代码参考php版:

// 假设已排序的待签名字符串为strToSign
//拼接支付密钥
$strToSign .= '&'.$sMerchantKey;
//SHA-256签名
$baSrc = mb_convert_encoding($strToSign,"UTF-8");
$baResult = hash('sha256', $baSrc);
//转为16进制字符串(可选)
$sign = bin2hex($baResult);


招行公钥验签示例

验签java示例:

public static boolean isValidSignature(String strToSign, String strSign, String publicKey)  
{  
    try   
    {  
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
        byte[] encodedKey = Base64.decode(publicKey);  
        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));    
      
        java.security.Signature signature = java.security.Signature
        .getInstance("SHA1WithRSA");  
      
        signature.initVerify(pubKey);  
        signature.update(strToSign.getBytes(“UTF-8”) );  
      
        boolean bverify = signature.verify( Base64.decode(strSign) );  
        return bverify;                
    }   
    catch (Exception e)   
    {  
        e.printStackTrace();  
    }  
      
    return false;  
}

待签名字符串strToSign 排序java示例:

JSONObject joNoticeData = joMain.getJSONObject("noticeData");

//按字典顺序排序,即字母顺序与大小写无关
List<String> keys = new ArrayList<String>(joNoticeData.keySet());
Collections.sort(keys, new Comparator<String>() {
   public int compare(String s1, String s2) {
     int i = s1.toLowerCase().compareTo(s2.toLowerCase());
     if (i != 0) {
         return i;
                }
         return s2.compareTo(s1);
         }
    });

    StringBuilder sb = new StringBuilder();
    for (String key : keys) {
         sb.append("&").append(key).append("=").append(joNoticeData.getString(key));
        }

验签php示例:

//公钥
$pub_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZs4l8Ez3F4MG0kF7RRSL+pn8MmxVE3nfdXzjx6d3rH8IfDbNvNRLS0X0b5iJnPyFO8sbbUo1Im4zX0M8XA0xnnviGyn5E6occiyUXJRgokphWb5BwaYdVhnLldctdimHoJTk3NFEQFav3guygR54i3tymrDc8lWtuG8EczVu8FwIDAQAB';
//待验证签名字符串
$toSign_str = 'branchNo=0101&dateTime=20160701123456&httpMethod=POST&merchantNo=123456&noticeSerialNo=201607019876543210&noticeType=ABCDEFGH&noticeUrl=http://99.12.38.88:8086/RecvNotice/NoticeRcv.ashx&param1=111&param2=a中转周末b';
//签名结果(strSign)
$sig_dat = 'Pez08MLS6tnrPTnO2febDbHmZ1FNB8Rgy1dp82XwPXkWbP0XPFZAy0ElRomJnMGuGNEwz9hC61TUNhRYhb22ZEHhFMpMNZWFeiN1ewXwIT5Sx7VmE4InfklQnVub0dRr1d6zJ3gprMHBoiQBe8xAxpd1y+82Jm5z7IkvLtgWXU4=';
//处理证书
$pem = chunk_split($pub_key, 64, "\n");
$pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----\n";
$pkid = openssl_pkey_get_public($pem);
if (empty($pkid)) {
    die('获取 pkey 失败');
}
//验证
$ok = openssl_verify($toSign_str, base64_decode($sig_dat), $pkid, OPENSSL_ALGO_SHA1);
var_dump($ok);
die();

验签C#示例(双击图标打开文件):

验签.zip



DES加密示例

注意:使用DES算法加密,加密需要取商户支付密钥的前8位,不足8位则右补0。
代码参考(C#):

public static byte[] DESEncrypt(byte[] plain, byte[] key)
{
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    des.Mode = CipherMode.ECB;
    des.Padding = PaddingMode.PKCS7;
    return des.CreateEncryptor(key, key).TransformFinalBlock(plain, 0, plain.Length);
}

public static byte[] DESDecrypt(byte[] encrypt, byte[] key)
{
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.ECB;
        des.Padding = PaddingMode.PKCS7;
        return des.CreateDecryptor(key, key).TransformFinalBlock(encrypt, 0, encrypt.Length);
}
//调用 
byte[] byteKey = Encoding.UTF8.GetBytes(sKey); 
byte[] baCiphertext =DESEncrypt(Encoding.UTF8.GetBytes(sBodyContent), byteKey); 
string sCiphertext = HexString(baCiphertext);

代码参考(JAVA):

public static byte[] DesEncrypt(byte[] plain, byte[] key) {
    try{
	SecureRandom random = new SecureRandom();
	DESKeySpec desKeySpec = new DESKeySpec(key);
	//创建一个密匙工厂,然后用它把DESKeySpec转换成
	SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
	SecretKey securekey = keyFactory.generateSecret(desKeySpec);
	//Cipher对象实际完成加密操作
	Cipher cipher = Cipher.getInstance("DES");//DES/ECB/PKCS5Padding
	//用密匙初始化Cipher对象
	cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
	//现在,获取数据并加密
	//正式执行加密操作
	return cipher.doFinal(plain);
    } catch(Throwable e) {
	    e.printStackTrace();
    }
    return null;
}
//调用 
try { 
    byte[] byteKey = desKey.getBytes("UTF-8"); 
    byte[] byteBodyContent = sBodyContent.getBytes("UTF-8"); 
    byte[] baCiphertext = TestDes.DesEncrypt(byteBodyContent, byteKey); 
    //将byte转为16进制字符串 
} catch (UnsupportedEncodingException e) { 
    // TODO Auto-generated catch block 
e.printStackTrace(); 
}


RC4加密示例

算法代码参考(C#):

/// <summary>
/// RC4加密。
/// RC4为对称加密算法,两次加密即为解密。明文/密文数据长度相同
/// <summary>
/// <param name="baSrc">明文数据</param>
/// <param name="nSrcLen">明文数据长度</param>
/// <param name="baKey">密钥</param>
/// <param name="nKeyLen">密钥长度</param>
/// <param name="baDst">密文数据</param>
/// <param name="nDstLen">密文数据长度</param>
/// <returns>加密数据长度。即明/密文数据长度</returns>
public static int RC4Encrypt(byte[] baSrc, int nSrcLen, byte[] baKey, int nKeyLen, byte[] baDst, int nDstLen)
{
    byte[] S = new byte[256];  //状态向量S
    byte[] T = new byte[256];  //临时向量T

    int i, j;
    //状态向量S的初始化
    for (i = 0; i < 256; i++)
    {
        S[i] = (byte)i;
        T[i] = baKey[i % nKeyLen];
    }

    j = 0;
    byte temp;

    for (i = 0; i < 256; i++)
    {
        j = (j + (int)S[i] + T[i]) % 256;
        temp = S[i];
        S[i] = S[j];
        S[j] = temp;
    }
    //状态向量S的初始化结束

    i = 0;
    j = 0;
    int t;
    char k;
    int n = 0;
    while (nSrcLen != 0)
    {
        i = (i + 1) % 256;
        j = (j + S[i]) % 256;
        temp = S[i];
        S[i] = S[j];
        S[j] = temp;
        t = (S[i] + S[j]) % 256;
        k = (char)S[t];
        baDst[n] = (byte)(baSrc[n] ^ k);
        n++;
        nSrcLen--;
    }
    return n;
}

调用:

byte[] baSrc = Encoding.UTF8.GetBytes(sSrc);
byte[] baKey = Encoding.UTF8.GetBytes(sKey);
byte[] baCiphertext = new byte[baSrc.Length];
RC4Encrypt(baSrc, baSrc.Length, baKey, baKey.Length, baCiphertext, baCiphertext.Length);
string sCiphertext = HexString(baCiphertext);