码农日记

薄洪涛的个人博客

不同语言AES加密结果不同

最近一直在和某保险公司的联调接口,他们的接口是AES加密过的,就是请求的报文体需要加密,返回的报文体需要解密;java实现的,然后我这边用php去调用,发现先了一件诡异的事情,两种语言的加密结果不一致!!!

以下是java代码

package com.aibaoxian.util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
 
 
public class AESUtil {
    private static final String defaultCharset = "UTF-8";
    private static final String KEY_AES = "AES";
    private static final String KEY_MD5 = "MD5";
    private static MessageDigest md5Digest;
    static {
        try {
            md5Digest = MessageDigest.getInstance(KEY_MD5);
        } catch (NoSuchAlgorithmException e) {
 
        }
    }
 
 
    //加密方法使用示例:
    public static void main(String[] args) throws Exception {
        //这个是aes加密的key,当然我这里是胡乱写的
        String key = "WVBJFZTESTERSS";
        String data = "{\"head\":{\"platform\":\"RBJF\",\"requestType\":10,\"timeStamp\":\"\",\"extTransactionNo\":\"\",\"localTransactionNo\":\"\",\"systemId\":\"\",\"MD5\":\"\",\"errorCode\":\"\",\"errorMessage\":\"\"},\"body\":{\"mainInfo\":{\"channelId\":\"CH10000020\",\"agentCode\":\"\",\"userId\":\"ABX999999\"}}}";
        String encrypted = AESUtil.encrypt(data, key);
        String decrypted = AESUtil.decrypt(encrypted, key);
        System.out.println("加密后的密文\n" + encrypted);
        System.out.println("解密后的报文:\n" + decrypted);
    }
    /**
     * 加密
     *
     * @param data 需要加密的内容
     * @param key 加密密码
     * @return
     */
    public static String encrypt(String data, String key) {
        return doAES(data, key, Cipher.ENCRYPT_MODE);
    }
    /**
     * 解密
     *
     * @param data 待解密内容
     * @param key 解密密钥
     * @return
     */
    public static String decrypt(String data, String key) {
        return doAES(data, key, Cipher.DECRYPT_MODE);
    }
 
 
    /**
     * 加解密
     *
     * @param data
     * @param key
     * @param mode
     * @return
     */
    private static String doAES(String data, String key, int mode) {
        try {
            boolean encrypt = mode == Cipher.ENCRYPT_MODE;
            byte[] content;
            if (encrypt) {
                content = data.getBytes(defaultCharset);
            } else {
                content = Base64.decodeBase64(data.getBytes());
            }
            SecretKeySpec keySpec = new SecretKeySpec(md5Digest.digest(key.getBytes(defaultCharset))
                    , KEY_AES);
            Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器
            cipher.init(mode, keySpec);// 初始化
            byte[] result = cipher.doFinal(content);
            if (encrypt) {
                return new String(Base64.encodeBase64(result));
            } else {
                return new String(result, defaultCharset);
            }
        } catch (Exception e) {
        }
        return null;
    }
}

可以看到,调用接口发送数据他是把key用md5加密后,再把报文体用aes加密,最后的结果用base64编码;接口返回的数据,要先进行base64解码,然后aes解码就是报文体;

class AESUtil{
    /**
     *
     * @param string $string 需要加密的字符串
     * @param string $key 密钥
     * @return string
     */
    public static function encrypt($string, $key){
        $key = substr(openssl_digest($key, 'md5', true), 0, 16);
        $data = openssl_encrypt($string, "AES-128-ECB", $key, OPENSSL_RAW_DATA);
        $data = base64_encode($data);
        return $data;
    }
    /**
     * @param string $string 需要解密的字符串
     * @param string $key 密钥
     * @return string
     */
    public static function decrypt($string, $key){
        $key = substr(openssl_digest($key, 'md5', true), 0, 16);
        @$decrypted = openssl_decrypt(base64_decode($string), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        return $decrypted;
    }
}

这是我最终调整后的php加密算法,和java的加解密是一致的;

之前的加密算法用的AES-128-CBC,开始解密结果是一致的,但是报文长度超过16位后,加密结果就不一样了

微信图片_20190615103540.png


后来改成了AES-128-ECB就可以了,原因是因为分块加密填充方式不同造成的;

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

版权所有 | 转载请标明出处