密码保护:python和java实现AES加密
在《golang实现RSA和AES加解密》一文有提到AES CFB加密方法,而里面有介绍golang官方使用的一段代码,而且在一个项目中就是使用了示例中的代码,所不同的,只不过是将其中的hex.DecodeString对应的key值做了更改。不过后来因为某些原因,想要使用其他语言实现下,发现使用起来还是有点蛋疼的。这里记录下其中的细节。
一、问题点
在致细研究其代码后发现如下规则:
1、golang CFB加解密官方示例使用的是AES 128位加密,而在很多语言里目前默认使用的是256位加密。
2、使用的key值,实际是使用的16位ascii码在进行16进制转换后得到的加密串,所以在golang里先使用了hex.DecodeString方法将其转为了明文密码(change this pass)。
3、iv的值是什么是无所谓的,所以在官方示例里,是make给了其16位的byte值,而后通过rand.Reader方法,每次得到的都是一个随机值,这样做的好处就是无规律可循,增加其安全性。
3、加密方法NewCFBEncrypter执行后,得出的是一个二进制数据(stream数据),后面使用的XORKeyStream方法后,可以将二进制数据进行16进制化,这点和大多数语言查到的示例,再base64实例化输出略有不同。当然,这里也支持通过base64方法实例化输出。
4、由于IV值每次都是随机的,所以每次通过XOR方法处理后,进行的输出结果都不同,但并不影响其解密,使用key最终都能正常解密。
5、最终输出的字符串的长度是aes.BlockSize+len(plaintext) 的两倍。
二、python实现
代码如下:
1#!/usr/bin/env python
2# code from www.361way.com
3import base64
4from Crypto.Cipher import AES
5#import binascii
6from binascii import b2a_hex, a2b_hex
7import os
8original_message = '{"Command": "free -m"}'
9a1 = "6368616e676520746869732070617373"
10key = a1.decode("hex")
11#key = 'change this pass'
12iv = os.urandom(16)
13MODE = AES.MODE_CFB
14BLOCK_SIZE = 16
15SEGMENT_SIZE = 128
16def _pad_string(value):
17 length = len(value)
18 pad_size = BLOCK_SIZE - (length % BLOCK_SIZE)
19 return value.ljust(length + pad_size, '\x00')
20def encrypt(key, iv, plaintext):
21 aes = AES.new(key, MODE, iv, segment_size=SEGMENT_SIZE)
22 plaintext = _pad_string(plaintext)
23 encrypted_text = aes.encrypt(plaintext)
24 return encrypted_text
25x = encrypt(key, iv, original_message)
26#encryptedpayload = base64.b64encode(encrypt(key, iv, original_message))
27print type(x)
28print b2a_hex(iv + x)
29#print binascii.hexlify(x)
30print original_message
31#print encryptedpayload
32#print encryptedpayload.decode()
类似于golang里的hex.DecodeString方法,这里使用的string decode方法,将其转为明文。而iv值,这里通过os.random(16)随机产生16位的值。上面的代码通过encrypt加密后返回的也是二进制乱码,无法正常输出,这里同上面一样,选择使用b2a_hex方法(binascii模块里方法)实现将结果输出为16进制字符串。而注释的base64部分,其实就是常见的实例化方法。
三、java实现
1import java.util.Base64;
2import java.util.Scanner;
3import javax.crypto.Cipher;
4import javax.crypto.spec.IvParameterSpec;
5import javax.crypto.spec.SecretKeySpec;
6/**
7 * Program to Encrypt/Decrypt String Using AES 128 bit Encryption Algorithm
8 */
9public class Tocmd {
10 private static final String encryptionKey = "6368616e676520746869732070617373";
11 private static final String characterEncoding = "UTF-8";
12 private static final String cipherTransformation = "AES/CFB/PKCS5PADDING";
13 private static final String aesEncryptionAlgorithem = "AES";
14public static String unHex(String arg) {
15 String str = "";
16 for(int i=0;i<arg.length();i+=2)
17 {
18 String s = arg.substring(i, (i + 2));
19 int decimal = Integer.parseInt(s, 16);
20 str = str + (char) decimal;
21 }
22 return str;
23}
24public static String bytesToHex(byte[] hashInBytes) {
25 StringBuilder sb = new StringBuilder();
26 for (byte b : hashInBytes) {
27 sb.append(String.format("%02x", b));
28 }
29 return sb.toString();
30 }
31 /**
32 * Method for Encrypt Plain String Data
33 * @param plainText
34 * @return encryptedText
35 */
36 public static String encrypt(String plainText,String skey) {
37 String encryptedText = "";
38 try {
39 Cipher cipher = Cipher.getInstance(cipherTransformation);
40 byte[] key = skey.getBytes(characterEncoding);
41 SecretKeySpec secretKey = new SecretKeySpec(key, aesEncryptionAlgorithem);
42 IvParameterSpec ivparameterspec = new IvParameterSpec(key);
43 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
44 byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF8"));
45 //Base64.Encoder encoder = Base64.getEncoder();
46 //encryptedText = encoder.encodeToString(cipherText);
47 encryptedText = bytesToHex(key) + bytesToHex(cipherText);
48 //encryptedText = bytesToHex(cipherText);
49 } catch (Exception E) {
50 System.err.println("Encrypt Exception : "+E.getMessage());
51 }
52 return encryptedText;
53 }
54 public static void main(String[] args) {
55 Scanner sc = new Scanner(System.in);
56 System.out.println("Enter String : ");
57 String plainString = sc.nextLine();
58 String skey = unHex(encryptionKey);
59 String encyptStr = encrypt(plainString,skey);
60 System.out.println("Plain String : "+plainString);
61 System.out.println("Encrypt String : "+encyptStr);
62 }
63}
由于本人不擅长java语言,所以这里的iv值的生成并未修改,这里的IV值使用的固定值,是由key的值搞出来的一个值,当然,想要生成一个16位byte的随机值应该并不麻烦。同样,这里并没有像网上抄来的哪些文章那样,直接base64实例输出,这里使用的unHex和bytesToHex方法,生成了一个类似golang里cfb输出的方法。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/python-java-aes/5868.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.