我正在研究如何使用 AES
进行跨平台(Android 和 Python)加密和解密,如果我使用基于 String
的 IV,我似乎可以成功传输数据。但如果我立即切换到使用由 SecureRandom.generateSeed()
生成的字节,就会出错。
key 是预先共享的。
工作的 Android 代码(删除了 try/catch block 以保持简短):
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);
有一个小的传输 header ,让客户端知道传入消息的大小,但我认为它不相关,因此我将其省略。 接收此消息的 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 进行一些操作。 .?
最佳答案
接收者需要知道 IV 是什么。查看 this Wikipedia entry 中有关 CBC 的部分:您可以看到加密的 n block 消息由 n+1 个 block 组成,附加 block 是 IV。没有标准的协议(protocol)来传输它,但我见过的每个代码都是通过在消息前面添加 IV 来实现这一点,这确实是很自然的事情,而且由于 CBC 的纠错特性,即使代码得到就有点不对劲了。例如,您可以在野外找到使用常量 IV 但在纯文本前面添加随机 block 的代码,这基本上以不同的方式执行相同的操作。有时您甚至会在书籍中找到此类代码,例如 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);
关于android - 解密适用于 String.getBytes() 的 IV,但会失败 SecureRandom.generateSeed(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20196658/