AES加密解密

栏目: 编程工具 · 发布时间: 5年前

内容简介:在项目开发中遇到AES加密解密的问题,因为一个参数问题卡了比较久,做个记录。并给出AES加密解密分别用Java、Python和C++的实现代码。AES加密算法即密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。AES加密算法涉及4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(

在项目开发中遇到AES加密解密的问题,因为一个参数问题卡了比较久,做个记录。并给出AES加密解密分别用 JavaPython 和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(String 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.getBytes(charSet));
        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 String 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 new String(encrypted, charSet);
    } 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

三、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算法简介


以上所述就是小编给大家介绍的《AES加密解密》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

LINUX与UNIX Shell编程指南

LINUX与UNIX Shell编程指南

David Tansley / 徐炎、张春萌 / 机械工业出版社 / 2000-6 / 38.00元

本书共分五部分,详细介绍了shell编程技巧,各种UNIX命令及语法,还涉及了UNIX下的文字处理以及少量的系统管理问题。本书内容全面、文字简洁流畅,适合Shell编程人员学习、参考。一起来看看 《LINUX与UNIX Shell编程指南》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具