如下的java代码,手动对block进行填充后,使其为16的整数倍后,加密的时候竟然强行再填充了16位,我在尝试用golang实现这段加密时,反复修改了很久,发现golang版的总是比java加密出来并base64的结果少了20位,于是把各个步骤中间结果打出来,发现并没有什么不同,然后尝试在golang后面强行追加了16个填充,那么填充什么呢?没错,我就是从0x0到0x10一个一个试出来的,最后发现当填充16个0x10时,golang跟java的加密结果就完全一样了,其实是按照pkcs5的填充规则的,例如需要填充n位,那么填充的值就是n,下面贴出golang跟java的两个代码:
PS: iv和key都是一模一样的。得到一个教训,当golang跟java在两种相同的模式下面如果加密出来的密文不同的时候就去尝试修改填充的方法吧,多尝试几次总是可以的。
java:
public static String aesEncrypt2(String appsecret, String data) throws Exception { //设置加密密钥 String key = appsecret.substring(16); System.out.println(key); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); //初始化向量 System.out.println("md5: " + DigestUtils.md5Hex(appsecret).substring(0, 16)); String iv = DigestUtils.md5Hex(appsecret).substring(0, 16); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); //设置加密模式 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //填充算法 int blockSize = cipher.getBlockSize(); byte[] dataBytes = data.getBytes(); int plaintextLength = dataBytes.length; if (plaintextLength % blockSize != 0) { plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); } byte[] plaintext = new byte[plaintextLength]; System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); System.out.println("填充后长度=" + plaintext.length); for(int i = 0;i < plaintext.length; i++) System.out.print(plaintext[i] + " "); //加密 cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(plaintext); System.out.println(""); for(int i = 0;i < encrypted.length;i++) System.out.print(encrypted[i] + " "); System.out.println(""); return Base64.encodeBase64String(encrypted); }
golang:
func GetMD5(cipherText string) string { md5Ctx := md5.New() md5Ctx.Write([]byte(cipherText)) cipherStr := md5Ctx.Sum(nil) return hex.EncodeToString(cipherStr)}func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize // padtext := bytes.Repeat([]byte{byte(padding)}, padding) for i := 0; i < padding; i++ { ciphertext = append(ciphertext, 0x0) } for i := 16; i < 32; i++ { ciphertext = append(ciphertext, 0x10) } fmt.Println(ciphertext) fmt.Printf("blocksieze[%d]\n", len(ciphertext)) // return append(ciphertext, padtext...) return ciphertext}func AesEncrypt(secret, data string) string { if len(secret) < 16 { log.Errorf("AesEncrypt secret[%s] length less 16") return "" } fmt.Println(secret[16:]) key := []byte(secret[16:]) iv := []byte(GetMD5(secret)[:16]) fmt.Println("md5: " + GetMD5(secret)[:16]) block, err := aes.NewCipher(key) if err != nil { log.Errorf("key error[%v]", err) return "" } ecb := cipher.NewCBCEncrypter(block, iv) content := PKCS5Padding([]byte(data), block.BlockSize()) crypted := make([]byte, len(content)) ecb.CryptBlocks(crypted, content) fmt.Println(crypted) return base64.StdEncoding.EncodeToString(crypted)}