我要分析一下java自我检查程序,这里是样本
public class tamper {
public static int checksum_self () throws Exception {
File file = new File ("tamper.class");
FileInputStream fr = new FileInputStream (file);
int result; // Compute the checksum
DigestInputStream sha = new DigestInputStream(fr, MessageDigest.getInstance("SHA"));
byte[] digest = sha.getMessageDigest();
int result = 12 // why???
for(int i=0;i<=digest;i++)
{
result = (result + digest[i]) % 16 /// modulus 16 to have the 16 first bytes but why ??
}
return result;
}
public static boolean check1_for_tampering () throws Exception {
return checksum_self () != 10;
}
public static void main (String args[]) throws Exception {
if (check1_for_tampering ()) {
System.exit (-1);
}
}
}
但我真的不明白为什么要做一个mod 16并把结果= 12?
答案 0 :(得分:2)
可能,因为没有模数,嵌入校验和将非常困难。想象一下,你已经编写了这个程序。你可以一次写下所有内容,但要有正确的校验和,你必须进行实验。
假设您编写校验和模4.在开始时将值与0进行比较。运行程序,但它检测到它被篡改。为什么?因为在编写完整的源代码之前,您不知道校验和。由于校验和值嵌入其中,因此源代码的每次更改都会更改校验和。
所以它就像一只追逐自己尾巴的狗。或者蛇吃它自己的尾巴。从技术上讲,这是一个带有反馈回路的动态系统的情况。好的,这就足够了类比。
使其发挥作用的唯一方法是进行实验。从校验和开始等于零并编译。很可能它会认识到它被篡改(不正确),因为你有大约1/4的概率(因为任何模4的值可以有4个值)来正确猜测。接下来,将值更改为1.如果它不是2,最后是3。
其中一个可以匹配,但模数值较低会降低检测篡改的可能性。所以价值16基本上是妥协。您希望保持模数值尽可能低,以获得相当低的猜测量。另一方面,你希望算法通过模数值高来防止篡改。
答案 1 :(得分:1)
mod 16不给出最后16个字节,甚至最低4位。它给出了n / 16的余数。这可以很容易地为负数并且不是累积摘要字节的好方法。
有两个随机文件产生相同结果的可能性为1/31。
我能想到的更简单的方法是
return new String(digest, 0).hashCode();
两个文件拥有相同哈希码的可能性为40亿,而且代码要短得多。
答案 2 :(得分:1)
这个示例代码的编写者可能不想检查摘要的整个16个字节,因此他决定从散列中创建一个散列,这就是mod 16操作的用途。它在模拟摘要的前16个字节16(更具体地说,它是摘要的4位摘要),然后将结果与10进行比较。 如果我错了,请纠正我,但我认为值12和10是随机选择的,以确保实际的哈希值和它检查的值是匹配的。
正如彼得所说,这不是一个完美的解决方案。