用Java测试加密和解密的单元

免责声明,我是iOS开发人员,一直在使用Android上的加密技术。 目前我已经设法在Android中实现加密,但我问自己一个单元如何测试加密和解密数据?

现在想到的第一个想法是:

String encryptedInputData = encryptedInputData("Hello"); String decryptedData = decryptData(encryptedInputData); Assert.assertEquals(decryptedData,"Hello"); 

然而,这个测试提出了一个缺陷……如果在encryptedInputDatadecryptData方法中确实发生了某些变化,那么这个测试就不会告诉它改变了什么以及为什么它现在正在破坏。 所以我想编写更细粒度的测试。 所以例如给出这个代码:

 Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] data = cipher.doFinal(message); 

我想确保cipher变量在ECB模式下使用RSA算法而没有填充。 我想测试.doFinal(message)中的.doFinal(message)遵循特定格式等。

现在我想象我能够模拟Cipher类,这里的问题是编写的加密和解密,仅作为Util类,并且能够对此进行unit testing,我将不得不通过模拟Cipher进入代码,假设这是一个Util类似乎会变得混乱,即我必须创建一个init方法只是为了unit testing目的或创建setter方法只是为了unit testing这个。 这将允许我对代码进行unit testing,但然后Util类使用我实际上不需要用于生产目的的代码变得笨拙。

是否有任何优雅的方式可以像这样unit testing场景? 即encryptedInputDatadecryptData是公共方法,但这些方法使用各种私有方法,坦率地需要进行unit testing,问题是如何?

真正的答案是你不应该这样做。 您永远不应该实现自己的加密例程。 您不仅非常容易弄错,还需要执行极其复杂的操作以确保实际上由于实现问题而无法进行攻击(例如,如果if语句的一个分支比另一个分支运行时间更长,你可以弄清楚支票的价值是多少)。 您应该始终使用开源,经过良好评估的库。

由于您没有自己实现它,因此您无需对其进行unit testing。 图书馆作家应该是。 如果您愿意,可以将他们的测试套件作为您自己的测试套件运行,但我认为这是浪费时间 – 他们在发布之前就已经完成了,而您最多只需要运行一次。

加布在重新发明轮子时真正保守的答案是正确的。 特别是当那个轮子是关于加密/安全/ ……这样的事情。 机会是:你会错的。 而黑客则喜欢那些试图使用自己的“安全加密技术”的人。

但要回答你的实际问题:尝试使用TDD (测试驱动开发)。 你看,你的问题是你创建了一些难以测试的API。

你是对的,你希望“端到端”像测试那样确保解密(加密(“某事”))带有“东西”。 现在你的问题是:如果你只用这两种方法编写你的代码; 然后单元测试很难。

因此:从一开始,当你考虑“我需要哪些课程”时; 和“你应该关注哪些方法”,你必须关注“我如何测试”。

换句话说:这是TDD非常重要的一个场合 – 因为你真的想设计可以测试的单元。 实现目标的最佳做法是:首先编写测试。 如果你设计你的单位,以便他们可以测试(因为你先写了测试); 惊喜 – 他们可以进行测试。 事后让它们“可测试”总是很麻烦; 最常见的是:接近不可能。

据我所知, Cipherjavax.crypto 类中 。 所以你不需要嘲笑它。

您可以编写unit testing来validation:1。 Key是否正确生成并且符合要求。 2.已成功创建CipherInputStream 。 3.将文本复制到文件并在解密后读取它确实匹配:

 @Test public void streamEncryptionDecryptionTest() { try { File file = tempFolder.newFile("test.txt"); String content = "This is the text content"; System.out.println("Original content for file = " + content); OutputStream fop = new FileOutputStream(file); byte[] key = EncryptionHelper.createKey(); fop = EncryptionHelper.getInstance(key).getEncryptedOutputStream(fop); // if file doesn't exists, then create it if (!file.exists()) { file.createNewFile(); } // get the content in bytes byte[] contentInBytes = content.getBytes(); fop.write(contentInBytes); fop.flush(); fop.close(); System.out.println("Encryption Done"); { // Read content w/o decryption InputStream fis = new FileInputStream(file); System.out.println("Content w/o decryption"); int contentChars; while ((contentChars = fis.read()) != -1) { // convert to char and display it System.out.print((char) contentChars); } } { // Decrypted content InputStream fis = new FileInputStream(file); fis = EncryptionHelper.getInstance(key).getDecryptedInputStream(fis); System.out.println("Total file size to read (in bytes) : " + fis.available()); System.out.println("Decrypted content"); int contentChars; while ((contentChars = fis.read()) != -1) { // convert to char and display it System.out.print((char) contentChars); } } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); Assert.assertTrue("security exception", false); } } 

虽然该测试没有明确的断言检查,但您可以添加:

 for (int i = 0; i < buffer.length; i++) { byte b = buffer[i]; System.out.print(b); decryptedContent[i] = b; } 

然后检查数组:

 Assert.assertArrayEquals(bytesEncoded, decryptedContent); 

请记住,您不应该通过将字节数组转换为字符串来比较字节数组,因为它会给您错误的实现。

  1. 部分缓冲区加密和解密正常工作。 根据您的需要。