zoukankan      html  css  js  c++  java
  • python笔记43-加解密AES/CBC/pkcs7padding

    前言

    有些公司对接口的安全要求比较高,传参数的时候,不会明文的传输,先对接口加密,返回的数据也加密返回。
    目前比较常见的加密方式是AES/CBC/pkcs7padding。

    AES五种加密模式

    在AES加密时,一般使用了“AES/ECB/NoPadding”或“AES/ECB/PKCS5padding” 或 “AES/ECB/PKCS5padding” 的模式
    使用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找到对应的解药!

    /**
     *
     * @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;
     }
    }
    

    测试

    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));
     }
    

    测试结果

    测试结果:
    加密前的: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位的时候,用去填充
    那么key应该是:12345678

    python代码 AES/CBC/pkcs7padding 加解密

    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('')
            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')  # 初始化密钥
        a = "1"
        print("加密前:%s" % a)
        b = pc.encrypt(a)
        print("解密后:%s" % b)
        print("大写变小写:%s" % b.lower())
    

    最后运行结果

    加密前:1
    解密后:B59227D86200D7FEDFB8418A59A8EEA9
    大写变小写:b59227d86200d7fedfb8418a59a8eea9
    

    参考相关的博客:https://www.cnblogs.com/chen-lhx/p/6233954.html
    https://blog.csdn.net/weixin_43107613/article/details/87875359

  • 相关阅读:
    树莓派成长日记03
    一些特殊文字的过滤Private Use Area:E000F8FF
    MongoDb 相关
    SQL 相关技术点收集贴
    正则表达式提取文本的日期
    MVC 相关技术点收集贴
    使用 json2.js注意点
    C#画图 GDI+
    PHP模拟POST,验证页面的返回状态
    EF-Entity Framework 相关技术点收集贴
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/11717282.html
Copyright © 2011-2022 走看看