我正在研究如何使用AES
进行跨平台(Android和Python)加密和解密,如果我使用基于String
的IV,我似乎成功传输数据。但是,如果我切换到使用SecureRandom.generateSeed()
生成的字节,它会立即出错。
密钥是预先共享的。
使用Android代码(删除try / catch块以保持简短):
String SecretKey = "0123456789abcdef";
String iv = "fedcba9876543210";
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
SecretKeySpec keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//Initialize the cipher
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
String message = "What's up?";
byte[] encrypted = cipher.doFinal(message.getBytes());
//Send the data
outputStream.write(encrypted);
有一个小的转移标题,让客户知道传入消息的大小,但我认为这是不相关的,我把它留了出来。 接收此消息的Python代码如下所示:
#Predefined:
unpad = lambda s : s[0:-ord(s[-1])]
encrypted = cs.recv(messagesize) # Receive the encrypted message
iv = encrypted[:16]
key = AES.new('0123456789abcdef', AES.MODE_CBC,IV=iv)
padded_msg = key.decrypt(encrypted[16:])
decrypted = unpad(padded_msg) #Remove padding
print "read [%s]" % decrypted
结果如下:
read [What's up]
如果我在Java代码中更改两行:
SecureRandom rnd = new SecureRandom();
IvParameterSpec ivspec = new IvParameterSpec(rnd.generateSeed(16));
Python输出变为:
read [?=H��m��lڈ�1ls]
我想知道SecureRandom会发生什么变化?我在默认情况下读取了String.getBytes()返回平台的默认编码(对于Android 4.0
),所以我想知道是否必须对Python结束使用SecureRandom生成的IV进行一些操作。?
答案 0 :(得分:2)
需要告知收件人IV是什么。查看this Wikipedia entry中关于CBC的部分:您可以看到加密的n块消息由n + 1个块组成,附加块是IV。传输它没有标准的协议,但是我看到的每个代码都是通过在信息中添加IV来实现的,这实际上是很自然的事情,并且由于CBC的纠错属性,即使代码获得有点不对劲。例如,您可以在野外找到使用常量IV的代码,但是使用随机块预先添加纯文本,这基本上以不同的方式执行相同的操作。有时你甚至会在书本中找到那种代码,比如David Hook第2章中的InlineIvCBCExample.java非常好book。
我建议采用以下方式进行AES / CBC / PKCS7Padding:
byte[] plaintext = ...;
byte[] key = ...;
// get iv
SecureRandom rnd = new SecureRandom();
byte[] iv = rnd.getBytes(16);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// encrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] ciphertext = cipher.doFinal(plaintext);
// copy to result
byte[] result = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(ciphertext, 0 , result, iv.length, ciphertext.length);