python3 AES加密解密


參考博客:https://blog.csdn.net/weixin_42068117/article/details/80084034 

  工作中開發人員用的是Java,但是寫mock用的是Python,所以Java的加密解密算法轉Python遇到了不少坑。下面以AES算法為例說明一下。

Java加密:

 1 /**
 2      * aes加密-128位
 3      * 
 4      */
 5     public static  String AesEncrypt(String content ,String key){
 6         if (StringUtils.isEmpty(key) || key.length() != 16) {
 7             throw new RuntimeException("密鑰長度為16位");
 8         }
 9         try {
10             String iv = key;
11             Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
12             int blockSize = cipher.getBlockSize();
13             byte[] dataBytes = content.getBytes("utf-8");
14             int plaintextLength = dataBytes.length;
15             if (plaintextLength % blockSize != 0) {
16                 plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
17             }
18             byte[] plaintext = new byte[plaintextLength];
19             System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
20             SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
21             IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
22             cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
23             byte[] encrypted = cipher.doFinal(plaintext);
24             return byte2Hex(encrypted);
25 
26         } catch (Exception e) {
27             throw new RuntimeException("aes加密發生錯誤", e);
28         }
29     }

Java解密:

 1     // ==Aes加解密==================================================================
 2     /**
 3      * aes解密-128位
 4      */
 5     public static String AesDecrypt(String encryptContent, String password) {
 6         if (StringUtils.isEmpty(password) || password.length() != 16) {
 7             throw new RuntimeException("密鑰長度為16位");
 8         }
 9         try {
10             String key = password;
11             String iv = password;
12             byte[] encrypted1 = hex2Bytes(encryptContent);
13             Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
14             SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
15             IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
16             cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
17             byte[] original = cipher.doFinal(encrypted1);
18             return new String(original,"UTF-8").trim();
19         } catch (Exception e) {
20             e.printStackTrace();
21             throw new RuntimeException("aes解密發生錯誤", e);
22         }
23     }

對應Python加密:

 1 def aes_encrypt(data, key):
 2     """aes加密函數,如果data不是16的倍數【加密文本data必須為16的倍數!】,那就補足為16的倍數
 3     :param key:
 4     :param data:
 5     """
 6     cipher = AES.new(key, AES.MODE_CBC, key)  # 設置AES加密模式 此處設置為CBC模式
 7     block_size = AES.block_size
 8     # 判斷data是不是16的倍數,如果不是用b'\0'補足
 9     if len(data) % block_size != 0:
10         add = block_size - (len(data) % block_size)
11     else:
12         add = 0
13     data += b'\0' * add
14     encrypted = cipher.encrypt(data)  # aes加密
15     result = binascii.b2a_hex(encrypted)  # b2a_hex encode  將二進制轉換成16進制
16     return result

Python解密:

1 def aes_decode(data, key):
2     """aes解密
3     :param key:
4     :param data:
5     """
6     cipher = AES.new(key, AES.MODE_CBC, key)
7     result2 = binascii.a2b_hex(data)  # 十六進制還原成二進制
8     decrypted = cipher.decrypt(result2)
9     return decrypted.rstrip(b'\0')  # 解密完成后將加密時添加的多余字符'\0'刪除

  從Java加密的代碼可以看出使用的是AES的CBC、128位模式,對應的Python加密也需要相同的模式,這里模式一定不要搞錯,否則加密的結果就不一樣了。

  加密的時候遇到一個比較坑的問題,就是Python加密時用的方法AES.new有三個參數,第一個參數是密鑰,第二個是模式,但是第三個參數就有點蒙了,之前在網上搜的結果是需要設置一個16位的字符,可以設置為b'0000000000000000'。但是加密后結果不對,這個參數不可以隨便設置,最后又回過頭來看了看Java的代碼,發現第三個參數和第一個參數設置的值是一樣的。。。

  還有個地方需要注意一下,就是Java算法中最后將字符串轉換成16進制了,所以轉換成Python的時候也需要轉換成16進制。

  解密的時候算法同上理。

  最后像這種Java轉Python的算法,一定要看清楚Java的每一步算法的處理方法,否則就坑大了。

以上


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM