android - 解密适用于 String.getBytes() 的 IV,但会失败 SecureRandom.generateSeed()

标签 android python encryption aes cbc-mode

我正在研究如何使用 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/

相关文章:

c# - TripleDESCryptoServiceProvider FIPS 140-2 合规性

android - 如何执行更新 UI View Android 的后台作业

带有整数运算的python re.sub

java - Python 脚本超时错误 Ambari

javascript - 使用 Javascript 解密 AES-256-CBC(加盐)密文

encryption - 可以为端到端加密的每条消息更改 key 对吗?

android - Google Drive API - Android - 如何获取驱动器文件 ID?

android - 如何检测Android应用何时进入后台并回到前台

android - 如何启动此 Activity 使用 adb shell am start -D -d pg/xx。 Activity 名称为 Main$Activity

python - 在 Plotly 中创建 3D 曲面图