---
sidebar_position: 9
slug: /dev/cdkey
---

# 98.9、中继CDKEY
:::tip[v1.7.0+]
在哪里发卡都可以，可以自己开发卡密商城，只要最后按一定的字段，和加密方式生成cdkey，就可以导入使用
:::

### 1、密钥
:::tip[说明]
加密密钥在服务端`server.json`里，使用这个密钥去加密，就可以在linker导入了
```
{
  "Relay": {
    "Cdkey": {
      "SecretKey": "snltty"
    }
  }
}
```
:::
### 2、CDKEY参数字段
:::tip[说明]
```
{
    "GB":100, //流量GB
    "Speed":100, //带宽 Mbps
    "Time":"1-0-0 0:0:0", //持续时间 年-月-日 时:分:秒
    "WidgetUserId":"2b9c9fef-c342-c968-9dc0-c15e3bc23646",//用户标识
    "OrderId":"ACG1234567890", //订单号
    "Contact":"111@qq.com", //联系方式
    "CostPrice":1, //成本元 double
    "Price":1, //原价元 double
    "UserPrice":1, //会员价元 double
    "PayPrice":1, //支付金额元 double
    "Count":1, //数量，导入后，会 GB*Count
    "Type":"Relay", //类型 固定 Relay
}
```
:::
### 3、加密方式AES-128-ECB
:::tip[说明]
1. C#样例
```
AesCrypto crypto = new AesCrypto("加密密钥", System.Security.Cryptography.PaddingMode.PKCS7);

//加密
byte[] bytes = crypto.Encode(jsonString);
string cdkey = Convert.ToBase64String(bytes);

public sealed class AesCrypto : ISymmetricCrypto
{
    private ICryptoTransform encryptoTransform;
    private ICryptoTransform decryptoTransform;

    public string Password { get; set; }

    public AesCrypto(string password, PaddingMode mode = PaddingMode.ANSIX923)
    {
        Password = password;
        using Aes aes = Aes.Create();
        aes.Padding = mode;
        (aes.Key, aes.IV) = GenerateKeyAndIV(password);

        encryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);
        decryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV);
    }
    public byte[] Encode(byte[] buffer)
    {
        return Encode(buffer, 0, buffer.Length);
    }
    public byte[] Encode(byte[] buffer, int offset, int length)
    {
        return encryptoTransform.TransformFinalBlock(buffer, offset, length);
    }
    public Memory<byte> Decode(byte[] buffer)
    {
        return Decode(buffer, 0, buffer.Length);
    }
    public Memory<byte> Decode(byte[] buffer, int offset, int length)
    {
        return decryptoTransform.TransformFinalBlock(buffer, offset, length);
    }
    public void Dispose()
    {
        encryptoTransform.Dispose();
        decryptoTransform.Dispose();
    }

    private (byte[] Key, byte[] IV) GenerateKeyAndIV(string password)
    {
        byte[] key = new byte[16];
        byte[] iv = new byte[16];

        using SHA384 sha = SHA384.Create();
        byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(password));

        Array.Copy(hash, 0, key, 0, key.Length);
        Array.Copy(hash, key.Length, iv, 0, iv.Length);
        return (Key: key, IV: iv);
    }

}
```
2. PHP样例
```
//加密
$aesCrypto = new AesCrypto("加密密钥");
$cdkey = base64_encode($aesCrypto->encode($jsonString));

class AesCrypto
{
    private $key;
    private $iv;
    private $password;

    public function __construct($password)
    {
        $this->password = $password;
        $this->initAes();
    }

    private function initAes()
    {
        $keyAndIV = $this->generateKeyAndIV($this->password);
        $this->key = $keyAndIV['key'];
        $this->iv = $keyAndIV['iv'];
    }

    public function encode($data)
    {
        return $this->encodeWithOffset($data, 0, strlen($data));
    }

    public function encodeWithOffset($data, $offset, $length)
    {
        $data = substr($data, $offset, $length);
        return openssl_encrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
    }

    public function decode($data)
    {
        return $this->decodeWithOffset($data, 0, strlen($data));
    }

    public function decodeWithOffset($data, $offset, $length)
    {
        $data = substr($data, $offset, $length);
        return openssl_decrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
    }

    private function generateKeyAndIV($password)
    {
        $hash = hash('sha384', $password, true);
        $key = substr($hash, 0, 16);
        $iv = substr($hash, 16, 16);
        return ['key' => $key, 'iv' => $iv];
    }
}
```
:::
