在文本文件的传输过程中,如:A将文件file,传给了B,但在传输的过程中,文件可能被C截获,并且C对文件file进行更改后变成file_alias,C再将file_alias传给B,这样B实际接受的是文件file_alias,而不是文件file。
解决方案
使用消息认证码(message authentication code,MAC)函数的密码秘钥加密策略,能够实现数据完整性和数据源的认证,另外这样作还可以以非常小的代价加密整个明文。MAC的基本思想是:对于每个需要通过网络进行传输的消息m,利用数学函数h计算出结果h(m),然后将结果赋给消息m本身。如果在消息的传输过程中出现了错误,比如所接受的消息a不同于发送的原始消息m。则消息接收者能够检测到异常:通过独立的计算h(a),并将计算结构与h(m)进行比较。如果结果不一致,则意味发生了异常。
与只使用纯粹的,简单的散列函数产生的消息摘要相比,MAC函数将秘密密钥加密与散列摘要函数结合起来,产生了一个值,只有拥有秘密密要的实体才能验证该值。用这种方法,MAC函数解决了数据完整性和数据源的认证。
示例程序:
import java.io.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
public class Jmac2 {
public Mac mac;
public Jmac2()throws Exception{
mac = Mac.getInstance("HmacMD5");
byte[] keybt="zhangjuwei".getBytes();
SecretKey key = new SecretKeySpec(keybt, "DESede");
mac.init(key);
}
//添加mac到文件
public void addMac(File file) throws Exception{
InputStreamReader read = new InputStreamReader (new FileInputStream(file),"UTF-8");
BufferedReader reader=new BufferedReader(read);
String line;
StringBuffer sb=new StringBuffer();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
System.out.println(sb.toString());
byte[] filebt=sb.toString().getBytes();
System.out.println("1 "+filebt.toString());
byte[] macCode = mac.doFinal(filebt);
System.out.println("2 "+new String(macCode,"UTF-8"));
System.out.println("3 "+macCode.length);
String macString=toHexString(macCode);
System.out.println("4 "+macString);
System.out.println("5 "+macString.length());
read.close();
//将mac追加写入文件
FileOutputStream fos=new FileOutputStream(file,true);
fos.write(macString.getBytes());
fos.close();
}
//读取带有mac的文件,并验证文件的完整性
public void checkMac(File file)throws Exception{
InputStreamReader read = new InputStreamReader (new FileInputStream(file),"UTF-8");
BufferedReader reader=new BufferedReader(read);
String line;
StringBuffer sb=new StringBuffer();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
int len=sb.length();
System.out.println("0 "+sb.toString());
String oldMacStr=sb.substring(len-32,len);
System.out.println("1 "+oldMacStr +" len="+oldMacStr.length());
String fileStr=sb.substring(0,len-32);
byte[] macCode = mac.doFinal(fileStr.getBytes());
System.out.println("2 "+new String(macCode,"UTF-8"));
System.out.println("3 "+macCode.length);
String newMacStr=toHexString(macCode);
System.out.println("4 "+newMacStr);
if(oldMacStr.equals(newMacStr)){
System.out.println("成功!");
}else{
System.out.println("失败!");
}
}
public static void main(String[] args)throws Exception{
Jmac2 mac2=new Jmac2();
//mac2.addMac(new File("D:/workspace/for_JSecurty.txt"));
mac2.checkMac(new File("D:/workspace/for_JSecurty.txt"));
}
//对mac转变格式16进制
public static String toHexString ( byte[] b ){
StringBuffer sb = new StringBuffer( b.length * 2 );
for ( int i=0; i<b.length; i++ ){
//look up high nibble char
sb.append( hexChar [( b[i] & 0xf0 ) >>> 4] );
//look up low nibble char
sb.append( hexChar [b[i] & 0x0f] );
}
return sb.toString();
}
static char[] hexChar = {
'0' , '1' , '2' , '3' ,
'4' , '5' , '6' , '7' ,
'8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f'};
}