# 用户数据的签名验证和加解密

# 说明

为了保证重要数据的私密性和完整性,使用了对称解密算法和签名对数据进行了保护。使用有效的 sessionKey 可以对数据进行解密和验签。

1.对称解密使用的算法为 AES-128-CBC,数据采用 PKCS#5 填充。

2.对称解密的目标密文为 Base64_Decode(encryptedData)。

3.对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是 16 字节。

4.对称解密算法初始向量 为 Base64_Decode(iv),其中 iv 由数据接口返回。

# 解密

    1.  encryptedData(string)    --------- Base64_decode --->     encryptedDataBytes(byte[])
    2.  encryptedDataBytes(byte[])      --- AES_decrypted ---->     plainBytes(byte[])
    3.  plainBytes(byte[]) ------------- new String() ------->    plainData(string json)

# 验签

开发者可以在自己的服务器端执行同样的算法,来校验数据是否合法。

sha1ToHex(rawData + sessionKey) == signature

# 解密的示例代码

public class AesCbcCoder {
    private static final Logger LOGGER = LoggerFactory.getLogger(AesCbcCoder.class);

    /**
     * 快手小程序返回的加密数据的解密函数
     *
     * @param sessionKey    有效的sessionKey,通过 login code 置换
     * @param encryptedData 返回的加密数据(base64编码)
     * @param iv            返回的加密IV(base64编码)
     * @return 返回解密的字符串数据
     */
    public static String decrypt(String sessionKey, String encryptedData, String iv) {
        // Base64解码数据
        byte[] aesKey = Base64.decodeBase64(sessionKey);
        byte[] ivBytes = Base64.decodeBase64(iv);
        byte[] cipherBytes = Base64.decodeBase64(encryptedData);

        byte[] plainBytes = decrypt0(aesKey, ivBytes, cipherBytes);

        return new String(plainBytes, StandardCharsets.UTF_8);
    }

    /**
     * AES解密函数. 使用 AES/CBC/PKCS5Padding 模式
     *
     * @param aesKey      密钥,长度16
     * @param iv          偏移量,长度16
     * @param cipherBytes 密文信息
     * @return 明文
     */
    private static byte[] decrypt0(byte[] aesKey, byte[] iv, byte[] cipherBytes) {
        SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(DECRYPT_MODE, keySpec, ivSpec);
            return cipher.doFinal(cipherBytes);
        } catch (Exception e) {
            LOGGER.error("decrypt error.", e);
            throw new RuntimeException(e);
        }
    }
}
Copyright ©2024, All Rights Reserved