• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

AES加密解密

2019年6月23日发布 | 最近更新于 2023年8月28日

在项目开发中遇到AES加密解密的问题,因为一个参数问题卡了比较久,做个记录。并给出AES加密解密分别用Java、Python和C++的实现代码。

一、AES简介

AES加密算法即密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。

AES加密算法涉及4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。数据块分组长度必须为128比特,密钥长度可以是128比特、192比特、256比特中的任意一个(如果数据块及密钥长度不足时,会补齐)。

解密算法的每一步分别对应加密算法的逆操作,加解密所有操作的顺序正好是相反的。

二、AES加密解密-Java实现

/**
 * PAD模式
 * NoPadding
 * PKCS7Padding
 * PKCS5Padding
 * PKCS1Padding
 */
private final String AES_PATTERN = "AES/CBC/NoPadding";
/**
 * AES加密KEY参数值,16个字符
 */
private final String AES_KEY = "aaaaaaaaaaaaaaaa";
/**
 * AES加密向量参数值,16个字符
 */
private final String AES_IV = "bbbbbbbbbbbbbbbb";
/**
 * 字符编码
 */
private final String CHARSET_ISO ="ISO8859-1"; 
/**
 * 解密
 *
 * @param content 要解密的文本内容,也可以直接替换成byte[]数组
 * @param pattern 模式参数
 * @param key     解密KEY值
 * @param iv      解密向量值
 * @param charSet 字符编码
 * @return
 */
public String decrypt(byte[] content, String pattern, String key, 
                      String iv, String charSet) {
    try {
        Cipher cipher = Cipher.getInstance(pattern);
        Key sKeySpec = new SecretKeySpec(key.getBytes(charSet), "AES");
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, 
                generateIV(iv.getBytes(charSet)));
        byte[] result = cipher.doFinal(content);
        return new String(result, charSet);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
/**
 * 加密
 *
 * @param content 要加密的文本内容,也可以直接替换成byte[]数组
 * @param pattern 模式参数
 * @param key     解密KEY值
 * @param iv      解密向量值
 * @param charSet 字符编码
 * @return
 */
public byte[] encrypt(String content, String pattern, String key,
                      String iv, String charSet) {
    try {
        Cipher cipher = Cipher.getInstance(pattern);
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(charSet), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, 
                new IvParameterSpec(iv.getBytes(charSet)));
        byte[] encrypted = cipher.doFinal(content.getBytes(charSet));
        return encrypted;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
/**
 * 初始化向量参数
 *
 * @param iv
 * @return
 * @throws Exception
 */
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
    AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
    params.init(new IvParameterSpec(iv));
    return params;
}

1)关于为何用”ISO8859-1″的编码方式,见Android AES加密报错处理:

javax.crypto.IllegalBlockSizeException: error:1e00007b:
Cipher functions:OPENSSL_internal:WRONG_FINAL_BLOCK_LENGTH

2)Padding参数要特别注意下
如果项目中配置文件用Python脚本加密了,解密要使用Java代码来实现,需要注意下Python脚本使用的Padding模式,就是因为在Python脚本的实现中,没有设置Padding参数,Java代码中设置了PKCS5Padding,使得解密一直出异常。如果是输出下面的异常,查下Padding参数是否设置正确。

java.lang.RuntimeException: javax.crypto.BadPaddingException: error:1e000065:
Cipher functions:OPENSSL_internal:BAD_DECRYPT 
java.lang.RuntimeException: javax.crypto.BadPaddingException: error:1e000065:
Cipher functions:OPENSSL_internal:BAD_DECRYPT
at java.lang.Thread.run(Thread.java:776) 
Caused by: javax.crypto.BadPaddingException: error:1e000065:
Cipher functions:OPENSSL_internal:BAD_DECRYPT
at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:568)
at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:350)
at javax.crypto.Cipher.doFinal(Cipher.java:2056)
... 4 more

3)如果是加密解密字符串,Padding参数用PKCS5Padding,AES_PATTERN的值调整为”AES/CBC/PKCS5Padding”,报如下的异常可以尝试修改Padding参数。

Caused by: javax.crypto.IllegalBlockSizeException: error:1e00006a:
Cipher functions:OPENSSL_internal:DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
 at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
 at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:568)
 at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:350)
 at javax.crypto.Cipher.doFinal(Cipher.java:2056)

三、AES加密解密-Python实现

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from binascii import b2a_hex, a2b_hex
from Crypto.Cipher import AES
import struct
import os

MODE = AES.MODE_CBC
KEY = ‘aaaaaaaaaaaaaaaa’
IV = ‘bbbbbbbbbbbbbbbb’

def aes_encrypt(content):
      cryptor = AES.new(KEY, MODE, IV)
      # 密钥key,长度:16(AES-128)、24(AES-192)、32(AES-256)
      length = 16
      count = len(content)
      if count < length:
            add = (length – count)
            content = content + (‘\0’ * add)
      elif count > length:
           add = (length – (count % length))
           content = content + (‘\0’ * add)
      encrypted = cryptor.encrypt(content)
      return encrypted

def aes_decrypt(content):
      cryptor = AES.new(KEY, MODE, IV)
      decrypt = cryptor.decrypt(content)
      return decrypt

def encrypt_file(input, output):
       if not os.path.exists(input):
            print(‘encrypt_file: input file %s not exits.’ % input)
            return

       print(“encrypt_file file %s to %s” % (input, output))
       with open(input, ‘r’) as origin:
               data = origin.read()
               encrypt_content = aes_encrypt(data)

               with open(output, ‘w’) as encrypt:
                      encrypt.write(encrypt_content)

def decrypt_file(input, output):
       if not os.path.exists(input):
            print(‘decrypt_file: input file %s not exits.’ % input)
            return

      print(“decrypt_file file %s to %s” % (input, output))
      with open(input, ‘r’) as origin:
            data = origin.read()
            decrypt_content = aes_decrypt(data)

            with open(output, ‘w’) as decrypt:
                  decrypt.write(decrypt_content)

四、AES加密解密-C++实现

/**
 * 加密
 */
gbool ConfigEncrypt(char *pData, int nLen, char **ppOutData, int *pnOutLen, 
                    char *KEY, char *VEC) {
     if (pData == NULL) {
         return gfalse;
     }
     char ivec[16] ={0} ;
     AES_KEY aes_ks1;
     int nRet = 0;
     char *pInData = NULL;
     int nBlock = 0;
     char *pOutData = NULL;
     int nOutLen = 0;
     if (pData <= 0) {
         return (gfalse);
     }
     int nTmpLen = 16 - nLen % 16;
     pInData = (char*)malloc(nLen + 64);
     memset(pInData, 0, nLen + 64);
     memcpy(pInData, pData, nLen);
     pOutData = (char*)malloc(nLen + 64);
     memset(pOutData, 0, nLen + 64);
     memcpy(ivec, VEC, 16u);
     nLen += nTmpLen;
     nRet = AES_set_encrypt_key((const unsigned char *)KEY, 128, &aes_ks1);
     AES_cbc_encrypt((const unsigned char *)pInData, (unsigned char *)pOutData, 
                    nLen + 16, &aes_ks1, (unsigned char *)ivec, AES_ENCRYPT);
     free(pInData);
     nOutLen = nLen + 16;
     *ppOutData = pOutData;
     *pnOutLen = nOutLen;
     return (gtrue);
}

/**
 * 解密
 */
gbool ConfigDecrypt(char *pData, int nLen, char **ppOutData, int *pnOutLen, 
                    char *KEY, char *VEC) {
     if (pData == NULL || nLen == 0) {
         return gfalse;
     }
     gbool bRet = gfalse;
     char ivec[16] ={0} ;
     AES_KEY aes_ks1 = {0};
     int nRet = 0;
     char *pTemp = NULL;
     if (pData <= 0) {
         return gfalse;
     }
     memcpy(ivec, VEC, sizeof(ivec));
     nRet = AES_set_decrypt_key((const unsigned char *)KEY, 128, &aes_ks1);
     pData = pData + 16;
     char *pDstData = (char*)calloc(nLen + 16, 1);
     if (pDstData) {
         AES_cbc_encrypt((const unsigned char *)pData, (unsigned char *)pDstData, 
                        nLen - 16, &aes_ks1, (unsigned char *)ivec, AES_DECRYPT);
         memcpy(pnOutLen, pDstData, 4);
         char *pOutData = (char *)calloc((*pnOutLen) + 1, 1);
         if (pOutData && *pnOutLen > 0)
         {
            memcpy(pOutData, pDstData + 4, *pnOutLen);
            *ppOutData = pOutData;
            bRet = gtrue;
         }
         free(pDstData);
         pDstData = NULL;
     }
     return bRet;
 }

五、参考资料

java学习-AES加解密之AES-128-CBC算法

ByteArrayOutputStream的内存溢出问题

Blocktype异常的几种解决办法

数据加密

JAVA AES加密与解密

AES算法简介

Cipher functions:EVP_DecryptFinal_ex:DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH

转载请注明出处:陈文管的博客 – AES加密解密

扫码或搜索:文呓

博客公众号

微信公众号 扫一扫关注

文章目录

  • 一、AES简介
  • 二、AES加密解密-Java实现
  • 三、AES加密解密-Python实现
  • 四、AES加密解密-C++实现
  • 五、参考资料
博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com