由于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();
}
}