前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python笔记43-加解密AES/CBC/pkcs7padding

python笔记43-加解密AES/CBC/pkcs7padding

作者头像
上海-悠悠
发布2019-10-24 20:17:05
3.3K0
发布2019-10-24 20:17:05
举报

前言

有些公司对接口的安全要求比较高,传参数的时候,不会明文的传输,先对接口加密,返回的数据也加密返回。

目前比较常见的加密方式是AES/CBC/pkcs7padding。

AES五种加密模式

在AES加密时,一般使用了“AES/ECB/NoPadding”或“AES/ECB/PKCS5padding” 或 “AES/ECB/PKCS7padding” 的模式

使用AES加密的ECB模式,显式指定加密算法为:CBC或CFB模式,可带上PKCS5Padding填充。AES密钥长度最少是128位,推荐使用256位 AES-ECB模式加密在加密和解密是需要一个初始化向量(Initialization Vector, IV),在每次加密之前或者解密之后,使用初始化向量与明文或密文异或。

分组密码有五种工作体制:

  • 1.电码本模式(Electronic Codebook Book (ECB));
  • 2.密码分组链接模式(Cipher Block Chaining (CBC));
  • 3.计算器模式(Counter (CTR));
  • 4.密码反馈模式(Cipher FeedBack (CFB));
  • 5.输出反馈模式(Output FeedBack (OFB))

AES算法是典型的【对称加密算法】,所谓对称加密,就是加密和解密的秘钥是一样的

JAVA加密

一般我们做接口自动化测试的时候,接口都是java写的,所以先得了解下java的加密方式。知道java对应的加密方式了,才能用python找到对应的解药!

代码语言:javascript
复制
/**
 *
 * @author ngh
 * AES128 算法
 *
 * CBC 模式
 *
 * PKCS7Padding 填充模式
 *
 * CBC模式需要添加一个参数iv
 *
 * 介于java 不支持PKCS7Padding,只支持PKCS5Padding 但是PKCS7Padding 和 PKCS5Padding 没有什么区别
 * 要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现
 */
public class AES {
 // 算法名称
 final String KEY_ALGORITHM = "AES";
 // 加解密算法/模式/填充方式
 final String algorithmStr = "AES/CBC/PKCS7Padding";
 //
 private Key key;
 private Cipher cipher;
 boolean isInited = false;

 byte[] iv = { 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 };
 public void init(byte[] keyBytes) {

  // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
  int base = 16;
  if (keyBytes.length % base != 0) {
   int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
   byte[] temp = new byte[groups * base];
   Arrays.fill(temp, (byte) 0);
   System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
   keyBytes = temp;
  }
  // 初始化
  Security.addProvider(new BouncyCastleProvider());
  // 转化成JAVA的密钥格式
  key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
  try {
   // 初始化cipher
   cipher = Cipher.getInstance(algorithmStr, "BC");
  } catch (NoSuchAlgorithmException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchPaddingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchProviderException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 /**
  * 加密方法
  *
  * @param content
  *            要加密的字符串
  * @param keyBytes
  *            加密密钥
  * @return
  */
 public byte[] encrypt(byte[] content, byte[] keyBytes) {
  byte[] encryptedText = null;
  init(keyBytes);
  System.out.println("IV:" + new String(iv));
  try {
   cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
   encryptedText = cipher.doFinal(content);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return encryptedText;
 }
 /**
  * 解密方法
  *
  * @param encryptedData
  *            要解密的字符串
  * @param keyBytes
  *            解密密钥
  * @return
  */
 public byte[] decrypt(byte[] encryptedData, byte[] keyBytes) {
  byte[] encryptedText = null;
  init(keyBytes);
  System.out.println("IV:" + new String(iv));
  try {
   cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
   encryptedText = cipher.doFinal(encryptedData);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return encryptedText;
 }
}

测试

代码语言:javascript
复制
ublic class Test {
 public static void main(String[] args) {
  AES aes = new AES();
//   加解密 密钥
  byte[] keybytes = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
  String content = "1";
  // 加密字符串
  System.out.println("加密前的:" + content);
  System.out.println("加密密钥:" + new String(keybytes));
  // 加密方法
  byte[] enc = aes.encrypt(content.getBytes(), keybytes);
  System.out.println("加密后的内容:" + new String(Hex.encode(enc)));
  // 解密方法
  byte[] dec = aes.decrypt(enc, keybytes);
  System.out.println("解密后的内容:" + new String(dec));
 }

测试结果

代码语言:javascript
复制
测试结果:加密前的:1
加密密钥:12345678
IV:0102030405060708
加密后的内容:b59227d86200d7fedfb8418a59a8eea9
IV:0102030405060708
解密后的内容:1

python加密

从上面的这一段JAVA代码中,我们需要知道的关键信息是,加密方式:AES/CBC/PKCS7Padding iv偏移量 byte[] iv = { 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 } 0x30 就是16进制的0, 所以iv = b’0102030405060708’, iv一般是16位 秘钥key虽然上面测试的key是12345678,但是key一般是16位,所以它上面有个if判断不足16位的时候,用\0去填充 那么key应该是:12345678\0\0\0\0\0\0\0\0

python代码 AES/CBC/pkcs7padding 加解密

代码语言:javascript
复制
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import algorithms
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import json

'''
AES/CBC/PKCS7Padding 加密解密
环境需求:
pip3 install pycryptodome
'''

class PrpCrypt(object):

    def __init__(self, key='0000000000000000'):
        self.key = key.encode('utf-8')
        self.mode = AES.MODE_CBC
        self.iv = b'0102030405060708'
        # block_size 128位

    # 加密函数,如果text不足16位就用空格补足为16位,
    # 如果大于16但是不是16的倍数,那就补足为16的倍数。def encrypt(self, text):
        cryptor = AES.new(self.key, self.mode, self.iv)
        text = text.encode('utf-8')

        # 这里密钥key 长度必须为16(AES-128),24(AES-192),或者32 (AES-256)Bytes 长度
        # 目前AES-128 足够目前使用

        text=self.pkcs7_padding(text)

        self.ciphertext = cryptor.encrypt(text)

        # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
        # 所以这里统一把加密后的字符串转化为16进制字符串
        return b2a_hex(self.ciphertext).decode().upper()

    @staticmethod
    def pkcs7_padding(data):
        if not isinstance(data, bytes):
            data = data.encode()

        padder = padding.PKCS7(algorithms.AES.block_size).padder()

        padded_data = padder.update(data) + padder.finalize()

        return padded_data

    @staticmethod
    def pkcs7_unpadding(padded_data):
        unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
        data = unpadder.update(padded_data)

        try:
            uppadded_data = data + unpadder.finalize()
        except ValueError:
            raise Exception('无效的加密信息!')
        else:
            return uppadded_data

    # 解密后,去掉补足的空格用strip() 去掉
    def decrypt(self, text):
        #  偏移量'iv'
        cryptor = AES.new(self.key, self.mode, self.iv)
        plain_text = cryptor.decrypt(a2b_hex(text))
        # return plain_text.rstrip('\0')
        return bytes.decode(plain_text).rstrip("\x01").\
            rstrip("\x02").rstrip("\x03").rstrip("\x04").rstrip("\x05").\
            rstrip("\x06").rstrip("\x07").rstrip("\x08").rstrip("\x09").\
            rstrip("\x0a").rstrip("\x0b").rstrip("\x0c").rstrip("\x0d").\
            rstrip("\x0e").rstrip("\x0f").rstrip("\x10")

    def dict_json(self, d):
        '''python字典转json字符串, 去掉一些空格'''
        j = json.dumps(d).replace('": ', '":').replace(', "', ',"').replace(", {", ",{")
        return j

# 加解密
if __name__ == '__main__':
    import json
    pc = PrpCrypt('12345678\0\0\0\0\0\0\0\0')  # 初始化密钥
    a = "1"
    print("加密前:%s" % a)
    b = pc.encrypt(a)
    print("解密后:%s" % b)
    print("大写变小写:%s" % b.lower())

最后运行结果

代码语言:javascript
复制
加密前:1
解密后:B59227D86200D7FEDFB8418A59A8EEA9
大写变小写:b59227d86200d7fedfb8418a59a8eea9
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从零开始学自动化测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • AES五种加密模式
  • python加密
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档