Android 解密与字符串为String.getBytes()的IV一起工作,但在SecureRandom.generateSeed()中失败

Android 解密与字符串为String.getBytes()的IV一起工作,但在SecureRandom.generateSeed()中失败,android,python,encryption,aes,cbc-mode,Android,Python,Encryption,Aes,Cbc Mode,我正在研究如何使用AES进行跨平台(Android和Python)加密和解密,如果我使用基于字符串的IV,我似乎成功地传输了数据。但如果我立即切换到使用SecureRandom.generateSeed()生成的字节,就会出问题。 密钥是预先共享的 工作Android代码(删除try/catch块以保持简短): 有一个小的传输头,让客户端知道传入消息的大小,但我认为这与此无关,所以我忽略了它。 接收此消息的Python代码如下所示: #Predefined: unpad = lambda s :

我正在研究如何使用
AES
进行跨平台(Android和Python)加密和解密,如果我使用基于
字符串的IV,我似乎成功地传输了数据。但如果我立即切换到使用
SecureRandom.generateSeed()
生成的字节,就会出问题。 密钥是预先共享的

工作Android代码(删除try/catch块以保持简短):

有一个小的传输头,让客户端知道传入消息的大小,但我认为这与此无关,所以我忽略了它。 接收此消息的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]
结果如下:

#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]

我想知道安全随机性有什么变化?我读到默认情况下字符串.getBytes()返回平台默认编码(适用于Android 4.0),因此我想知道是否必须对使用SecureRandom生成的IV的Python端进行一些操作。

需要告诉接收者IV是什么。查看中的CBC部分:您可以看到加密的n块消息由n+1块组成,额外的块是IV。没有传输它的标准协议,但我看到的每一个代码都是通过在消息前加上IV来实现的,这真的是很自然的事情,这要归功于CBC的纠错特性,即使代码稍微出错,它也能工作。例如,您可以在野外找到使用常量IV但在纯文本前添加随机块的代码,这基本上以不同的方式完成相同的任务。有时你甚至会在书中找到这种代码,比如David Hook的第2章中的InlineIvCBCExample.java

我建议使用以下方法进行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);

你是如何将IV传输到python端的?@wallenborn,据我所知,它是CBC加密的前置,因为它是第一个块的一部分。。但是,这个领域对我来说是新的,所以可能有一个错误的地方。但不管怎样,我想知道问题是否真的存在,因为我没有触及传输代码,只是客户端上的IV版本发生了变化,但大小应该是相同的,所以这让我想,也许我在格式方面出了问题…@wallenborn,原来你在钱的问题上是对的!昨晚我太累了,以至于没有注意到在尝试失败后立即执行的是旧代码(硬编码iv和secret)。我修改了Java代码,将生成的iv前置到加密的字节,现在从流中获取前16个字节,就可以得到预期效果的iv。如果你不介意把你的答案扩大一点,我会选择它作为答案。谢谢你花时间回答!这确实是我摔倒了,我不知怎么的觉得IV应该在第一个街区……不客气。有了所有的ivSpec和cipher.init内容,很容易在这个问题上绊倒。