Golang AES算法与 java(android)的互通

1,608 阅读2分钟

由于Java AES256 加密库受出口限制,所以只采用AES 128加密。

互通要达到的要求

  • 加密位数:统一采AES 128
  • 分组加密条件:CBC/PKCS#5PADDING
  • 密钥填充方式一样

因为android的默认填充与java默认不一样,而且在不同的JDK版本里也会出现key填充不一致的情况,所以自己手动填充,Go也采取与java一样的填充方式:不满16位补零。AES两个平台均要实现AES的加密与解密操作。加密结果转成base64。

关键代码如下所示: go:

//填充
func paddingkey(key string)  (string){
	var buffer bytes.Buffer
	buffer.WriteString(key)

	for i:=len(key);i<16;i++{
		buffer.WriteString("0")
	}

	return buffer.String()
}
//加密
func En(src string,srckey string)(string){
	key := []byte(paddingkey(srckey))
	result, err := AesEncrypt([]byte(src), key)
	if err != nil {
		panic(err)
	}
	return 	base64.StdEncoding.EncodeToString(result)
}
//解密
func UnEn(src string,srckey string)(string) {

	key := []byte(paddingkey(srckey))


	var result []byte
	var err error

	result,err=base64.StdEncoding.DecodeString(src)
	if err != nil {
		panic(err)
	}
	origData, err := AesDecrypt(result, key)
	if err != nil {
		panic(err)
	}
	return string(origData)

}
func AesEncrypt(origData, key []byte,IV []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	origData = PKCS5Padding(origData, blockSize)
	// origData = ZeroPadding(origData, block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, IV[:blockSize])
	crypted := make([]byte, len(origData))
	// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
	// crypted := origData
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

func AesDecrypt(crypted, key []byte,IV []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block,IV[:blockSize])
	origData := make([]byte, len(crypted))
	// origData := crypted
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(origData)
	// origData = ZeroUnPadding(origData)
	return origData, nil
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	// 去掉最后一个字节 unpadding 次
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}


java:

public class AEStool {
    private IvParameterSpec ivSpec;
    private SecretKeySpec keySpec;

    public AEStool(String srckey) {
        String key=paddingkey(srckey);
        try {
            byte[] keyBytes = key.getBytes();
            byte[] buf = new byte[16];
            for (int i = 0; i < keyBytes.length && i < buf.length; i++) {
                buf[i] = keyBytes[i];
            }
            this.keySpec = new SecretKeySpec(buf, "AES");
            this.ivSpec = new IvParameterSpec(keyBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public String encrypt(String src) {
        try {
            byte[] origData=src.getBytes();
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, this.keySpec, this.ivSpec);
            byte[] re= cipher.doFinal(origData);
            return Base64.encodeToString(re,Base64.DEFAULT);
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String decrypt(String src) throws Exception {

            byte[]  crypted=Base64.decode(src,Base64.DEFAULT);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, this.keySpec, this.ivSpec);
            byte re[] =cipher.doFinal(crypted);
            return new String(re);
    }
    private static String paddingkey(String liu) {
        StringBuffer sb=new StringBuffer(liu);
        for(int i=liu.length();i<16;i++)
        {
            sb.append("0");
        }
        return sb.toString();

    }
}