Skip to content

加密算法指南

优先使用 SDK

官方 SDK 已内置全部加密算法,强烈建议直接使用 SDK 进行对接。如果找不到你的开发语言的 SDK,可参考以下代码自行实现,具体细节请参考 SDK 源码

RSA 非对称加密

加密方向与常规相反

  • 请求加密:客户端用 公钥加密 → 服务器用 私钥解密
  • 响应解密:服务器用 私钥加密 → 客户端用 公钥解密

RSA 加密有数据长度限制,超过需要分段处理

密钥长度加密分段大小解密分段大小
1024 位117 字节(128 - 11)128 字节
2048 位245 字节(256 - 11)256 字节

公钥加密(请求参数)

python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

def rsa_encrypt(data, public_key_pem):
    key = RSA.import_key(public_key_pem)
    cipher = PKCS1_v1_5.new(key)
    key_size = key.size_in_bytes()
    block_size = key_size - 11

    data_bytes = data.encode('utf-8')
    encrypted = b''
    offset = 0
    while offset < len(data_bytes):
        block = data_bytes[offset:offset + block_size]
        encrypted += cipher.encrypt(block)
        offset += block_size
    return encrypted.hex().upper()
javascript
const crypto = require('crypto');

function rsaEncrypt(data, publicKeyPem) {
    const dataBytes = Buffer.from(data, 'utf-8');
    const keySize = 128; // 1024位密钥
    const blockSize = keySize - 11;
    const blocks = [];
    let offset = 0;
    while (offset < dataBytes.length) {
        const block = dataBytes.slice(offset, offset + blockSize);
        blocks.push(crypto.publicEncrypt(
            { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_PADDING },
            block
        ));
        offset += blockSize;
    }
    return Buffer.concat(blocks).toString('hex').toUpperCase();
}
java
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;

public static String rsaEncrypt(String data, PublicKey publicKey, int keySize) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    int blockSize = keySize - 11;
    byte[] dataBytes = data.getBytes("UTF-8");
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int offset = 0;
    while (offset < dataBytes.length) {
        int len = Math.min(blockSize, dataBytes.length - offset);
        out.write(cipher.doFinal(dataBytes, offset, len));
        offset += len;
    }
    return bytesToHex(out.toByteArray()).toUpperCase();
}
c
// 使用内置 RSA 实现(不依赖 OpenSSL)
unsigned char* rsa_encrypt(const char* data, int data_len,
                           const BIGNUM* n, const BIGNUM* e,
                           int key_size, int* out_len) {
    int block_size = key_size - 11;
    int blocks = (data_len + block_size - 1) / block_size;
    unsigned char* result = malloc(blocks * key_size);
    *out_len = 0;
    int offset = 0;
    while (offset < data_len) {
        int chunk = (data_len - offset < block_size) ? data_len - offset : block_size;
        // PKCS1 填充 + 模幂运算: pow(padded_block, e, n)
        rsa_pkcs1_encrypt(data + offset, chunk, n, e, key_size,
                          result + *out_len);
        *out_len += key_size;
        offset += chunk;
    }
    return result;
}

公钥解密(响应数据)

python
from Crypto.Util.number import bytes_to_long, long_to_bytes

def rsa_decrypt(hex_data, public_key_pem):
    key = RSA.import_key(public_key_pem)
    n, e = key.n, key.e
    key_size = key.size_in_bytes()
    encrypted = bytes.fromhex(hex_data)

    decrypted = b''
    offset = 0
    while offset < len(encrypted):
        block = encrypted[offset:offset + key_size]
        block_int = bytes_to_long(block)
        dec_int = pow(block_int, e, n)               # 模幂运算
        dec_block = long_to_bytes(dec_int, key_size)
        pad_end = dec_block.index(b'\x00', 2)         # 去除 PKCS1 填充
        decrypted += dec_block[pad_end + 1:]
        offset += key_size
    return decrypted.decode('utf-8')
javascript
function rsaDecrypt(hexData, n, e, keySize) {
    const encrypted = Buffer.from(hexData, 'hex');
    const blocks = [];
    let offset = 0;
    while (offset < encrypted.length) {
        const block = encrypted.slice(offset, offset + keySize);
        let blockInt = bufferToBigInt(block);
        let decInt = modPow(blockInt, e, n);          // 模幂运算
        let decBlock = bigIntToBuffer(decInt, keySize);
        // 去除 PKCS1 填充
        let padEnd = -1;
        for (let i = 2; i < decBlock.length; i++) {
            if (decBlock[i] === 0x00) { padEnd = i; break; }
        }
        blocks.push(padEnd !== -1 ? decBlock.slice(padEnd + 1) : decBlock);
        offset += keySize;
    }
    return Buffer.concat(blocks).toString('utf-8');
}
java
public static String rsaDecrypt(String hexData, BigInteger n, BigInteger e, int keySize) {
    byte[] encrypted = hexToBytes(hexData);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int offset = 0;
    while (offset < encrypted.length) {
        byte[] block = Arrays.copyOfRange(encrypted, offset, offset + keySize);
        BigInteger blockInt = new BigInteger(1, block);
        BigInteger decInt = blockInt.modPow(e, n);    // 模幂运算
        byte[] decBlock = bigIntToBytes(decInt, keySize);
        // 去除 PKCS1 填充
        int padEnd = 2;
        while (padEnd < decBlock.length && decBlock[padEnd] != 0x00) padEnd++;
        out.write(decBlock, padEnd + 1, decBlock.length - padEnd - 1);
        offset += keySize;
    }
    return out.toString("UTF-8");
}

RC4 对称流式加密

加密和解密使用同一函数、同一密钥

python
def rc4(data, key):
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + ord(key[i % len(key)])) % 256
        S[i], S[j] = S[j], S[i]

    i = j = 0
    result = []
    for char in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        result.append(chr(ord(char) ^ S[(S[i] + S[j]) % 256]))
    return ''.join(result)
javascript
function rc4(data, key) {
    const S = Array.from({ length: 256 }, (_, i) => i);
    let j = 0;
    for (let i = 0; i < 256; i++) {
        j = (j + S[i] + key.charCodeAt(i % key.length)) % 256;
        [S[i], S[j]] = [S[j], S[i]];
    }

    let i = 0; j = 0;
    let result = '';
    for (const char of data) {
        i = (i + 1) % 256;
        j = (j + S[i]) % 256;
        [S[i], S[j]] = [S[j], S[i]];
        result += String.fromCharCode(char.charCodeAt(0) ^ S[(S[i] + S[j]) % 256]);
    }
    return result;
}
java
public static String rc4(String data, String key) {
    int[] S = new int[256];
    for (int i = 0; i < 256; i++) S[i] = i;
    int j = 0;
    for (int i = 0; i < 256; i++) {
        j = (j + S[i] + key.charAt(i % key.length())) % 256;
        int tmp = S[i]; S[i] = S[j]; S[j] = tmp;
    }

    int ii = 0; j = 0;
    StringBuilder result = new StringBuilder();
    for (char c : data.toCharArray()) {
        ii = (ii + 1) % 256;
        j = (j + S[ii]) % 256;
        int tmp = S[ii]; S[ii] = S[j]; S[j] = tmp;
        result.append((char)(c ^ S[(S[ii] + S[j]) % 256]));
    }
    return result.toString();
}
c
void rc4(const char* data, int data_len, const char* key, int key_len, char* out) {
    unsigned char S[256];
    for (int i = 0; i < 256; i++) S[i] = i;
    int j = 0;
    for (int i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % key_len]) % 256;
        unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
    }

    int i = 0; j = 0;
    for (int k = 0; k < data_len; k++) {
        i = (i + 1) % 256;
        j = (j + S[i]) % 256;
        unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
        out[k] = data[k] ^ S[(S[i] + S[j]) % 256];
    }
}

DES-ECB 对称分组加密

使用 ECB 模式 + PKCS7 填充,密钥固定 8 字节。

python
from Crypto.Cipher import DES
import base64

def des_encrypt(data, key):
    cipher = DES.new(key.encode(), DES.MODE_ECB)
    pad_len = 8 - len(data.encode()) % 8
    padded = data + chr(pad_len) * pad_len
    return base64.b64encode(cipher.encrypt(padded.encode())).decode()

def des_decrypt(data, key):
    cipher = DES.new(key.encode(), DES.MODE_ECB)
    decrypted = cipher.decrypt(base64.b64decode(data))
    return decrypted[:-decrypted[-1]].decode()
javascript
const crypto = require('crypto');

function desEncrypt(data, key) {
    const cipher = crypto.createCipheriv('des-ecb', key, null);
    cipher.setAutoPadding(true); // PKCS7
    let encrypted = cipher.update(data, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

function desDecrypt(data, key) {
    const decipher = crypto.createDecipheriv('des-ecb', key, null);
    let decrypted = decipher.update(data, 'base64', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

自定义 Base64 编码

使用后台配置的 64 个字符替换标准 Base64 编码表,编码集必须恰好 64 个不重复字符

python
import base64

class CustomBase64:
    STANDARD_CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

    def __init__(self, custom_charset):
        if len(custom_charset) != 64:
            raise ValueError("自定义字符集必须是64位字符")
        self.custom_charset = custom_charset
        self.encode_trans = str.maketrans(self.STANDARD_CHARSET, self.custom_charset)
        self.decode_trans = str.maketrans(self.custom_charset, self.STANDARD_CHARSET)

    def encode(self, data):
        if isinstance(data, str):
            data = data.encode('utf-8')
        standard_b64 = base64.b64encode(data).decode('ascii')
        return standard_b64.translate(self.encode_trans)

    def decode(self, data):
        standard_b64 = data.translate(self.decode_trans)
        return base64.b64decode(standard_b64).decode('utf-8')
javascript
class CustomBase64 {
    constructor(customCharset) {
        if (customCharset.length !== 64)
            throw new Error('自定义字符集必须是64位字符');
        this.standardCharset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
        this.customCharset = customCharset;
    }

    encode(data) {
        let standardB64 = Buffer.from(data, 'utf-8').toString('base64');
        let result = '';
        for (let i = 0; i < standardB64.length; i++) {
            const idx = this.standardCharset.indexOf(standardB64[i]);
            result += idx !== -1 ? this.customCharset[idx] : standardB64[i];
        }
        return result;
    }

    decode(data) {
        let standardB64 = '';
        for (let i = 0; i < data.length; i++) {
            const idx = this.customCharset.indexOf(data[i]);
            standardB64 += idx !== -1 ? this.standardCharset[idx] : data[i];
        }
        return Buffer.from(standardB64, 'base64').toString('utf-8');
    }
}
java
public class CustomBase64 {
    private static final String STANDARD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    private final String customCharset;

    public CustomBase64(String customCharset) {
        if (customCharset.length() != 64)
            throw new IllegalArgumentException("自定义字符集必须是64位字符");
        this.customCharset = customCharset;
    }

    public String encode(String data) {
        String standard = java.util.Base64.getEncoder().encodeToString(data.getBytes());
        StringBuilder sb = new StringBuilder();
        for (char c : standard.toCharArray()) {
            int idx = STANDARD.indexOf(c);
            sb.append(idx != -1 ? customCharset.charAt(idx) : c);
        }
        return sb.toString();
    }

    public String decode(String data) {
        StringBuilder sb = new StringBuilder();
        for (char c : data.toCharArray()) {
            int idx = customCharset.indexOf(c);
            sb.append(idx != -1 ? STANDARD.charAt(idx) : c);
        }
        return new String(java.util.Base64.getDecoder().decode(sb.toString()));
    }
}
c
static const char STANDARD[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

char* custom_b64_encode(const char* data, int len, const char* charset) {
    char* standard = base64_encode(data, len);  // 标准 Base64 编码
    for (int i = 0; standard[i]; i++) {
        const char* p = strchr(STANDARD, standard[i]);
        if (p) standard[i] = charset[p - STANDARD];
    }
    return standard;
}

char* custom_b64_decode(const char* data, const char* charset) {
    char* buf = strdup(data);
    for (int i = 0; buf[i]; i++) {
        const char* p = strchr(charset, buf[i]);
        if (p) buf[i] = STANDARD[p - charset];
    }
    return base64_decode(buf);  // 标准 Base64 解码
}

T3 网络验证 WebAPI 开发文档