我的任务是在项目上实施AES加密。参考代码是用Java编写的 - 它需要转换为Python。在组织我的笔记写一个SO问题时,我不小心偶然发现了答案!希望其他人认为这有用,我将在这里提到我的笔记作为“分享你的知识”的问题。
要求是使用具有给定密钥的AES加密消息。以下是参考代码(Java中)的简要介绍,
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Encoder;
public class EncryptAES {
private static String toHexString(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; ++i) {
String s = Integer.toHexString(data[i] & 0XFF);
buf.append((s.length() == 1) ? ("0" + s) : s);
}
return buf.toString();
}
public static String encrypt(String input, String key) {
byte[] crypted = null;
try {
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey);
crypted = cipher.doFinal(input.getBytes());
final String encryptedString = toHexString(Base64.encodeBase64(crypted));
return encryptedString;
} catch (Exception e) {
System.out.println(e.toString());
}
return new String(new BASE64Encoder().encode(crypted));
}
public static void main(String[] args) {
String key = args[0];
String plaintext = args[1];
System.out.println("KEY = " + key);
System.out.println("PLAINTEXT = " + plaintext);
System.out.println("CIPHER = " + EncryptAES.encrypt(plaintext, key));
}
}
如果将上述内容保存为“EncryptAES.java”并将库文件commons-codec-1.7.jar
保存在同一目录中,则可以使用以下命令对其进行编译,
$ javac EncryptAES.java -cp commons-codec-1.7.jar
这是运行程序几次时的输出,
$ java -cp "commons-codec-1.7.jar:." EncryptAES ddddffffeeeerrrr message
KEY = ddddffffeeeerrrr
MESSAGE = message
CRYPTO = 397a59594d35524e6b6a463253706f41467668646b773d3d
$
$ java -cp "commons-codec-1.7.jar:." EncryptAES qqqqwwwweeeerrrr ThisIsAVeryImportantMessage
KEY = qqqqwwwweeeerrrr
PLAINTEXT = ThisIsAVeryImportantMessage
CIPHER = 56536a384d667736756b595a394e396b6d504d736231444673375250736d5639596f637072792f6e4b424d3d
$
环顾四周,我找到了Python Crypto库。这是我必须复制上述输出的早期尝试之一,
#!/usr/bin/python
import sys
from Crypto.Cipher import AES
if __name__ == '__main__':
key = sys.argv[1]
plaintext = sys.argv[2]
print 'KEY = ' + key
print 'PLAINTEXT = ' + plaintext
encobj = AES.new(key, AES.MODE_ECB)
ciphertext = encobj.encrypt(plaintext)
print 'CIPHER = ' + ciphertext.encode('hex')
这不太符合我的需要。相反,我收到一条关于输入字符串的错误消息,该字符串需要是16的倍数。这让我接下来的尝试,
#!/usr/bin/python
import sys
from Crypto.Cipher import AES
# ref: https://gist.github.com/crmccreary/5610068
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
class AESCipher:
def __init__( self, key ):
"""
Requires hex encoded param as a key
"""
self.key = key.decode("hex")
def encrypt( self, raw ):
"""
Returns hex encoded encrypted value!
"""
raw = pad(raw)
cipher = AES.new(self.key, AES.MODE_ECB)
return cipher.encrypt(raw).encode("hex")
if __name__ == '__main__':
key = sys.argv[1]
plaintext = sys.argv[2]
print 'KEY = ' + key
print 'PLAINTEXT = ' + plaintext
# ref: http://stackoverflow.com/a/16882092
hex_key = "".join("{:02x}".format(ord(c)) for c in key)
encryptor = AESCipher(hex_key)
ciphertext = encryptor.encrypt(plaintext)
print 'CIPHER = ' + ciphertext
说实话,我不确定输出是什么,
$ python EncryptAES2.py ddddffffeeeerrrr message
KEY = ddddffffeeeerrrr
PLAINTEXT = message
CIPHER = f7361833944d9231764a9a0016f85d93
$
我尝试了很多东西 - 不同的加密模式,博客,SO问题,并放弃了自己寻找解决方案。就在这时,我决定收集我的笔记并在这里提出一个问题。现在,如果我没有列出我的尝试,那就不会有太多意义了,所以我开始将它们组织在一个文件夹中并标记为EncryptAES.py
,EncryptAES2.py
..等等。
答案 0 :(得分:3)
当我准备列表时,灵感震惊了我,为了我的最后一次尝试,我决定用十六进制重新格式化输出。令我惊喜的是,它奏效了!这是获奖代码,
#!/usr/bin/python
import sys
import base64
from Crypto.Cipher import AES
# ref: http://stackoverflow.com/a/12525165
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
class AESCipher:
def __init__( self, key ):
self.key = key
def encrypt( self, raw ):
raw = pad(raw)
cipher = AES.new(self.key, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(raw))
if __name__ == '__main__':
key = sys.argv[1]
plaintext = sys.argv[2]
print 'KEY = ' + key
print 'PLAINTEXT = ' + plaintext
encryptor = AESCipher(key)
ciphertext = encryptor.encrypt(plaintext)
hex_ciphertext = "".join("{:02x}".format(ord(c)) for c in ciphertext)
print 'CIPHER = ' + hex_ciphertext
这里的参考是使用我用于Java示例的早期输入的输出,
$ python EncryptAES3.py ddddffffeeeerrrr message
KEY = ddddffffeeeerrrr
PLAINTEXT = message
CIPHER = 397a59594d35524e6b6a463253706f41467668646b773d3d
$
$ python EncryptAES3.py qqqqwwwweeeerrrr ThisIsAVeryImportantMessage
KEY = qqqqwwwweeeerrrr
PLAINTEXT = ThisIsAVeryImportantMessage
CIPHER = 56536a384d667736756b595a394e396b6d504d736231444673375250736d5639596f637072792f6e4b424d3d
$
获得此解决方案带给我很多反复试验。如果有一种更加严谨的方法将Java转换为Python,我很乐意听到它!
答案 1 :(得分:1)
采用@chronodekar 的答案并将其更改为适用于 Python 3.9。
Python 3 的 PyCryptoDome 版本引发了一个类型错误:对象类型
class simple_AES:
def __init__(self, key):
self.key = bytearray(key.encode())
def encrypt_AES(self, raw):
raw = bytearray(pad(raw).encode())
cipher = AES.new(self.key, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(raw))
但是,我也遇到了输出问题。我找到了将输出转换为十六进制 python base64 to hex 的答案。
hex_ciphertext = base64.b64decode(ciphertext).hex()
print('CIPHER = ' + hex_ciphertext)
答案 2 :(得分:0)
Set rng = ThisWorkbook.Sheets("Edit Entry").Range("M31:M41")
For each cell in rng
If cell.interior.Colorindex = 15 then
If Not Intersect(Target, Range("M31:M41")) Is Nothing then
Msgbox "NOT AN EDITABLE FIELD.", vbCritical + vbOkOnly, "NO DATA ENTRY"
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
End If
End If
Next Cell