Java中加密和解密的单元测试
免责声明,我是一名iOS开发者,一直在Android上玩加密游戏。目前,我已经设法在Android中实现了加密,但我在问自己,一个单元如何测试数据的加密和解密 现在我想到的第一个想法是:Java中加密和解密的单元测试,java,android,unit-testing,encryption,Java,Android,Unit Testing,Encryption,免责声明,我是一名iOS开发者,一直在Android上玩加密游戏。目前,我已经设法在Android中实现了加密,但我在问自己,一个单元如何测试数据的加密和解密 现在我想到的第一个想法是: String encryptedInputData = encryptedInputData("Hello"); String decryptedData = decryptData(encryptedInputData); Assert.assertEquals(decryptedData,"Hello");
String encryptedInputData = encryptedInputData("Hello");
String decryptedData = decryptData(encryptedInputData);
Assert.assertEquals(decryptedData,"Hello");
然而,这个测试带来了一个缺陷。。。如果encryptedInputData
和DecryptedData
方法中发生了更改,则此测试不会说明更改的内容以及现在中断的原因。所以我想写更多的粒度测试。例如,给定以下代码:
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] data = cipher.doFinal(message);
我想确保cipher
变量在ECB模式下使用RSA算法,没有填充。我想测试.doFinal(message)
中的消息是否遵循特定格式等
现在我想象我能够模拟密码
类,这里的问题是,编写的加密和解密只作为一个Util类,为了能够对其进行单元测试,我必须将模拟密码
传递到代码中,考虑到这是一个Util类,它看起来会变得混乱,也就是说,为了单元测试的目的,我必须创建一个init方法just,或者创建setter方法来进行单元测试。这将允许我对代码进行单元测试,但随后Util类会变得笨重,代码实际上并不需要用于生产目的
有没有什么优雅的方法可以对这样的场景进行单元测试?i、 e.encryptedInputData
和DecryptedData
是公共方法,但这些方法使用各种私有方法,坦率地说,这些方法需要进行单元测试,问题是如何进行测试?真正的答案是您不必这样做。您不应该实现自己的加密例程。不仅您很可能会出错,还需要做一些极其复杂的事情来确保它实际上由于实现问题而不可被破解(例如,如果if语句的一个分支比另一个分支运行时间长,您可以计算出检查的值)。您应该始终使用一个开源的、经过良好审查的库
因为您没有自己实现它,所以不需要对它进行单元测试。图书馆的作者应该是。如果你喜欢它,运行他们的测试套件作为你自己的一部分,但我会认为这是浪费时间-他们在发布之前做了,你真的只需要运行它最多一次。< /P> < P > Gabe是正确的回答“强”>真的非常/强-当重新发明轮子时是保守的;特别是当这个轮子是关于加密/安全的时候。。。这样的事情。机会是:你会弄错的。黑客们喜欢那些试图用他们自己的“安全密码”来对付他们的人
但要回答您的实际问题:尝试使用(测试驱动开发)。你看,你的问题是你创建了一些很难测试的API
您是正确的,您希望类似“端到端”的测试确保解密(加密(“某物”)与“某物”一起提供。现在你的问题是:如果你在编写代码时只考虑了这两种方法;然后,单元测试很难
因此:从一开始,当你考虑“我需要哪些课程”时;以及“哪些方法进入哪个类”你必须关注“我如何测试它”
换句话说:这是TDD非常重要的场合之一,因为您确实希望设计可以测试的单元。实现这一目标的最佳实践是:首先编写测试。如果您设计了单元,以便可以对其进行测试(因为您首先编写了测试);惊喜-他们可以测试。让他们在事后“可测试”总是很麻烦;最常见的情况是:几乎不可能。据我所知,Cipher
在javax.crypto
中。所以你不需要嘲笑它
您可以编写单元测试来验证:
1. <代码>键
正确生成,并且与要求匹配。
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);