价格解密算法示例¶
Note
可以使用的测试数据:
enckey:ABE53CC1B7FDA2903681192D105A53EC sigkey:da2d9026aa90400cbc9c4db053e65b82 加密价格:ebHrWLBZ_vQ8id_wknHJAw 实际价格:3500
PHP¶
<?php
/*-------------------------example------------------------------*/
$PriceDec = new PriceDec($encKey, $sigKey);
$price = $PriceDec->decode($enPrice);
var_dump($price);
/*-------------------------example------------------------------*/
class PriceDec
{
protected $encKey;
protected $sigKey;
public function __construct($encKey, $sigKey)
{
$this->encKey = hex2bin($encKey);
$this->sigKey = hex2bin($sigKey);
}
public function decode($base64Str)
{
$data = $this->base64urlDecode($base64Str);
if (!$data || strlen($data) != 16) {
return false;
}
$timeMsStamp = substr($data, 0, 4);
$encPrice = substr($data, 4, 8);
$sig = substr($data, 12, 4);
$pad = hex2bin(hash_hmac('sha1', $timeMsStamp, $this->encKey));
$decPrice = $this->xorBytes($pad, $encPrice, 8);
$price = unpack('d', $decPrice);
if (!isset($price[1])) {
return false;
}
$osig = hex2bin(hash_hmac('sha1', $decPrice . $timeMsStamp, $this->sigKey));
if ($sig != substr($osig, 0, strlen($sig))) {
return false;
}
return $price[1];
}
protected function xorBytes($s1, $s2, $length)
{
$result = "";
for ($i = 0; $i < 8; ++ $i) {
$result .= chr(ord($s1[$i]) ^ ord($s2[$i]));
}
return $result;
}
protected function base64urlDecode($base64Str)
{
$base64Str = str_replace(array('-','_'), array('+','/'), $base64Str);
$base64Len = strlen($base64Str);
$pad = 4 - ($base64Len % 4);
$pad < 4 && $base64Str = str_pad($base64Str, $base64Len + $pad, "=");
return base64_decode($base64Str);
}
}
JAVA¶
import java.io.UnsupportedEncodingException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.nio.ByteBuffer;
import java.util.Base64;
import javax.xml.bind.DatatypeConverter;
import java.math.BigInteger;
class PriceDec
{
private byte[] encKey;
private byte[] sigKey;
public void Price()
{
}
public void setEncKey(String encKey)
{
this.encKey = hex2bin(encKey);
}
public void setSigKey(String sigKey)
{
this.sigKey = hex2bin(sigKey);
}
public double decode(String base64Str)
{
byte[] temp = base64UrlDecode(base64Str);
if (temp.length != 16) {
throw new RuntimeException("base64UrlDecode string length less 16");
}
byte[] timeStamp = new byte[4];
byte[] encPrice = new byte[8];
byte[] sig = new byte[4];
timeStamp = Arrays.copyOfRange(temp,0,4);
encPrice = Arrays.copyOfRange(temp, 4,12);
sig = Arrays.copyOfRange(temp, 12,16);
byte[] pad = hex2bin(hmac_sha1(timeStamp, this.encKey));
byte[] decPrice = xorBytes(pad, encPrice, 8);
double d = byteArrToDouble(decPrice);
int i=0;
byte[] calByte = new byte[12];
for (i=0;i<8;i++) {
calByte[i] = decPrice[i];
}
for (i=0;i<4;i++) {
calByte[8+i] = timeStamp[i];
}
byte[] osig = hex2bin(hmac_sha1(calByte, this.sigKey));
byte[] compareSig = Arrays.copyOfRange(osig, 0,4);
if (!Arrays.equals(sig, compareSig)) {
throw new RuntimeException("sig not equal");
}
return d;
}
public byte[] xorBytes(byte[] padStr, byte[] encPrice, int n)
{
int i;
byte[] retArr = new byte[n];
for (i=0;i<n;i++) {
retArr[i] = (byte)(padStr[i]^encPrice[i]);
}
return retArr;
}
public byte[] base64UrlDecode(String base64Str)
{
base64Str = base64Str.replaceAll("-", "+");
base64Str = base64Str.replaceAll("_", "/");
int length = base64Str.length();
int pad = 4-(length%4);
int i;
for (i=0;i<pad;i++) {
base64Str += "=";
}
byte[] bytes = base64Str.getBytes();
byte[] decoded = Base64.getDecoder().decode(base64Str);
return decoded;
}
public double byteArrToDouble(byte[] b) {
long l;
l = b[0];
l &= 0xff;
l |= ((long) b[1] << 8);
l &= 0xffff;
l |= ((long) b[2] << 16);
l &= 0xffffff;
l |= ((long) b[3] << 24);
l &= 0xffffffffl;
l |= ((long) b[4] << 32);
l &= 0xffffffffffl;
l |= ((long) b[5] << 40);
l &= 0xffffffffffffl;
l |= ((long) b[6] << 48);
l &= 0xffffffffffffffl;
l |= ((long) b[7] << 56);
return Double.longBitsToDouble(l);
}
public byte[] hex2bin(String hex) {
char[] hex2char = hex.toCharArray();
byte[] bytes = new byte[hex.length() / 2];
int temp;
for (int i = 0; i < bytes.length; i++) {
temp = Character.digit(hex2char[2 * i], 16) * 16;
temp += Character.digit(hex2char[2 * i + 1],16);
bytes[i] = (byte) (temp & 0xff);
}
return bytes;
}
private String hmac_sha1(byte[] value, byte[] key) {
try {
byte[] keyBytes = key;
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(value);
String hexBytes = DatatypeConverter.printHexBinary(rawHmac);
return hexBytes;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**----------------begin使用范例---------------------**/
public class pricedec{
public static void main(String args[]) {
PriceDec p = new PriceDec();
p.setEncKey($encKey);
p.setSigKey($sigKey);
String base64Str = $enPrice;
System.out.println(p.decode(base64Str));
}
}
/**----------------end 使用范例---------------------**/
golang¶
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"strings"
)
func main() {
fmt.Println(Decode("这是dec_key", "这是sig_key", "这是price_enc"))
}
func Decode(dec_key, sig_key, price_enc string) (float64, error) {
data, err := base64url_decode(price_enc)
if err != nil {
return 0, err
}
if len(data) != 16 {
return 0, errors.New("Illegal base64 string")
}
time_ms_stamp_bytes := data[:4]
enc_price := data[4:12]
sig := data[12:16]
dec_key_bytes := hex2bin(dec_key)
pad := sha1_hmac(time_ms_stamp_bytes, dec_key_bytes)
dec_price := xor_bytes(pad, enc_price, 8)
var price float64
dec_price_buf := bytes.NewBuffer(dec_price)
binary.Read(dec_price_buf, binary.LittleEndian, &price)
//校验
sig_key_bytes := hex2bin(sig_key)
osig := sha1_hmac(append(dec_price, time_ms_stamp_bytes...), sig_key_bytes)
if bytes.Compare(sig, osig[:len(sig)]) == 0 {
//校验成功
return price, nil
}
return price, errors.New("signature is illegal")
}
func xor_bytes(b1, b2 []byte, length int) []byte {
new_b := make([]byte, length)
for i := 0; i < length; i++ {
new_b[i] = b1[i] ^ b2[i]
}
return new_b
}
func hex2bin(s string) []byte {
ret, _ := hex.DecodeString(s)
return ret
}
func sha1_hmac(data, key []byte) []byte {
mac := hmac.New(sha1.New, key)
mac.Write(data)
return mac.Sum(nil)
}
func base64url_encode(data []byte) string {
ret := base64.StdEncoding.EncodeToString(data)
return strings.Map(func(r rune) rune {
switch r {
case '+':
return '-'
case '/':
return '_'
}
return r
}, ret)
}
func base64url_decode(s string) ([]byte, error) {
base64Str := strings.Map(func(r rune) rune {
switch r {
case '-':
return '+'
case '_':
return '/'
}
return r
}, s)
if pad := len(base64Str) % 4; pad > 0 {
base64Str += strings.Repeat("=", 4-pad)
}
return base64.StdEncoding.DecodeString(base64Str)
}
C#¶
using System;
using System.Linq;
using System.Security.Cryptography;
class demo
{
public static void Main(string[] args)
{
PriceDec a = new PriceDec();
Console.WriteLine(a.decode($encKey,$sigKey,$enPrice));
Console.ReadKey(true);
}
}
public class PriceDec
{
public double decode(string enc_key, string sig_key, string price)
{
byte[] data = this.base64UrlDecode(price);
if (data==null|| data.Length != 16)
{
throw new ArgumentException("The price is not a valid string");
}
byte[] encKey = hex2Bin(enc_key);
byte[] sigKye = hex2Bin(sig_key);
byte[] timeMsStamp = data.Take(4).ToArray();
byte[] encPrice = data.Skip(4).Take(8).ToArray();
byte[] sig = data.Skip(12).Take(4).ToArray();
byte[] pad = hash_hmac(timeMsStamp, encKey);
byte[] dec_price= xorBytes(pad, encPrice, 8);
byte[] osigData = new byte[dec_price.Length + timeMsStamp.Length];
dec_price.CopyTo(osigData,0);
timeMsStamp.CopyTo(osigData, dec_price.Length);
byte[] osig = hash_hmac(osigData, sigKye);
if(!sig.SequenceEqual(osig.Take(4).ToArray())){
throw new ArgumentException("The price is not a complete string");
}
return BitConverter.ToDouble(dec_price, 0);
}
private byte[] hex2Bin(string hexdata)
{
if (hexdata == null)
throw new ArgumentNullException("hexdata");
if (hexdata.Length % 2 != 0)
throw new ArgumentException("hexdata should have even length");
byte[] bytes = new byte[hexdata.Length / 2];
for (int i = 0; i < hexdata.Length; i += 2)
bytes[i / 2] = (byte)(HexValue(hexdata[i]) * 0x10
+ HexValue(hexdata[i + 1]));
return bytes;
}
static int HexValue(char c)
{
int ch = (int)c;
if (ch >= (int)'0' && ch <= (int)'9')
return ch - (int)'0';
if (ch >= (int)'a' && ch <= (int)'f')
return ch - (int)'a' + 10;
if (ch >= (int)'A' && ch <= (int)'F')
return ch - (int)'A' + 10;
throw new ArgumentException("Not a hexadecimal digit.");
}
private byte[] hash_hmac(byte[] signatureString, byte[] secretKey, bool raw_output = false)
{
HMACSHA1 hmac = new HMACSHA1(secretKey);
hmac.ComputeHash(signatureString);
return hmac.Hash;
}
protected byte[] xorBytes(byte[] s1, byte[] s2, int length)
{
byte[] result = new byte[length];
for (int i = 0; i < length; i++)
{
result[i] = Convert.ToByte((int)s1[i] ^ (int)s2[i]);
}
return result;
}
protected byte[] base64UrlDecode(string base64Str)
{
base64Str = base64Str.Replace("-", "+");
base64Str = base64Str.Replace("_", "/");
int base64Len = base64Str.Length;
int pad = 4 - (base64Len % 4);
if (pad < 4) base64Str = base64Str.PadRight(base64Len + pad, '=');
return Convert.FromBase64String(base64Str);
}
}