基于JavaMail的邮件客户端--JustLook(四、邮件的本地存储与安全性问题)

 

上图是软件登陆后的界面截图,此时还没有接收邮件所以右侧为空,下面出于个人隐私遮盖了邮件地址。左侧是一个树形结构,收件箱内容为邮箱中存在的邮件,其余包含的内容都存储在本地。

每个邮箱对应一个文件夹,可以打开文件:

因为我已经对文件内容进行了加密,所以打开文件只能看到这些。而在软件中打开邮件时看到的则是解密后的内容。

 

邮件的本地存储

 熟悉OutLook的朋友,应该会知道OutLook是将邮件以未解析的形式存储,地址应该为C:/Documents and Settings/“userName”/Application Data/Microsoft/Outlook/,新装的系统没有用过OutLook不确定是这个,如果不是请见谅。而我存储的是解析后的邮件内容。存储文件明文的结构形式大体如下:

<Email>

    <Title>

       <From></From>

       <TO></TO>

    </Title>

    <Body>

        <Text></Text>

        <Attach></Attach>

    </Body>

</Email>

以一种类似HTML代码的形式组织解析后邮件的内容信息。

安全性处理

很显然上述类似HTML代码的内容信息不安全,所以对它进行了加解密的处理。使用Sun公司提供的JCE应用程序编程接口中的PBEWithMD5And-DES算法,对本地文件信息进行加密和解密。当用户进入本地文件夹时,系统从相应位置读取文件内容解密后存储至内存,用户选择要打开的邮件后,从内存中选取数据,显示在阅读邮件窗体中。做Java的开发就是这样的简单,自己不必非要亲自去写加解密算法,拿来用就好了,大家都学过鲁迅先生批判拿来主义那篇文章“去其糟粕取其精华”,计算机的领域太广了,对于很多方面的东西,我们也只是用的时候拿来用,无法真正的深入到知识的层面。像这里用到的PBEWithMD5And-DES,你根本不用关心是如何实现的,找个例子照搬就行了,只需要改变参数就好了,不知道这是一件幸事还是无奈之举呢。言归正传,在这里我们只需要修改两个主要参数的值,一个是种子,一个是盐值。

CipherCodeFactory类用来生成加密、解密类的对象实例,代码如下:

package edu.cie.ciphercode;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEParameterSpec;

public class CipherCodeFactory {
 public static javax.crypto.Cipher createEncryptCipher(String password){
  javax.crypto.spec.PBEKeySpec keySpec = new javax.crypto.spec.PBEKeySpec(password.toCharArray());
  SecretKeyFactory keyFactory = null;
  SecretKey secretKey = null;
  PBEParameterSpec parameterSpec = null;
  javax.crypto.Cipher cipher = null;
  byte []salt = {(byte)0x24, (byte)0x63, (byte)0x11, (byte)0xa4,
     (byte)0xd2, (byte)0xdc, (byte)0x4w, (byte)0xf1,};//此处为盐值,可以自己设置
  int iterationCount = 100;//迭代次数
  try {
   keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
   secretKey = keyFactory.generateSecret(keySpec);
   parameterSpec = new PBEParameterSpec(salt, iterationCount);
   cipher = Cipher.getInstance("PBEWithMD5AndDES");
   cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  } catch (InvalidKeySpecException e) {
   e.printStackTrace();
  } catch (NoSuchPaddingException e) {
   e.printStackTrace();
  } catch (InvalidKeyException e) {
   e.printStackTrace();
  } catch (InvalidAlgorithmParameterException e) {
   e.printStackTrace();
  }
    
  return cipher;
 }
 
 public static javax.crypto.Cipher createDecryptCipher(String password){
  javax.crypto.spec.PBEKeySpec keySpec = new javax.crypto.spec.PBEKeySpec(password.toCharArray());
  SecretKeyFactory keyFactory = null;
  SecretKey secretKey = null;
  PBEParameterSpec parameterSpec = null;
  javax.crypto.Cipher cipher = null;
  byte []salt = {(byte)0x24, (byte)0x63, (byte)0x11, (byte)0xa4,
     (byte)0xd2, (byte)0xdc, (byte)0x4w, (byte)0xf1,};//此处为盐值,可以自己设置
  int iterationCount = 100;//迭代次数
  try {
   keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
   secretKey = keyFactory.generateSecret(keySpec);
   parameterSpec = new PBEParameterSpec(salt, iterationCount);
   cipher = Cipher.getInstance("PBEWithMD5AndDES");
   cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  } catch (InvalidKeySpecException e) {
   e.printStackTrace();
  } catch (NoSuchPaddingException e) {
   e.printStackTrace();
  } catch (InvalidKeyException e) {
   e.printStackTrace();
  } catch (InvalidAlgorithmParameterException e) {
   e.printStackTrace();
  }
    
  return cipher;
 }
}
 

DecryptAndEncryptFile类代码如下:

package edu.cie.ciphercode;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;

import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;

public class DecryptAndEncryptFile {
 
 public static final String PATH = "C:" + java.io.File.separator + "JustLook"
 + java.io.File.separator;
 public static javax.crypto.Cipher encrypt = null;
 public static javax.crypto.Cipher decrypt = null;
 
 public DecryptAndEncryptFile(String key){
  encrypt = edu.cie.ciphercode.CipherCodeFactory.createEncryptCipher("111111");//此处为种子值,由你设定但必须想同
  decrypt = edu.cie.ciphercode.CipherCodeFactory.createDecryptCipher("111111");
 }
 
 public String decryptFile(String fileName, String filePath) {
  String temp = "";
  String path = PATH + filePath;

  File file = new File(path, fileName);
  System.out.println("PATH: " + file.toString());

  if (!file.exists()) {
   try {
    file.createNewFile();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }

  FileInputStream inputStream = null;

  try {
   inputStream = new FileInputStream(file);
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  }

  CipherInputStream in = new CipherInputStream(inputStream, decrypt);
  Vector<Byte> fileBytes = new Vector<Byte>();

  try {
   byte contents = (byte) in.read();
   while (contents != -1) {
    fileBytes.add(new Byte(contents));
    contents = (byte) in.read();
   }
   in.close();
  } catch (IOException e) {
   e.printStackTrace();
  }

  byte[] text = new byte[fileBytes.size()];
  for (int i = 0; i < fileBytes.size(); i++) {
   text[i] = ((Byte) fileBytes.elementAt(i)).byteValue();
  }
  temp = new String(text);

  return temp;
 }

 public boolean encryptFile(String fileName, String text, String filePath) {
  boolean flag = false;
  String path = PATH + filePath;

  File save = new File(path, fileName);
  FileOutputStream fileOutputStream = null;

  try {
   fileOutputStream = new FileOutputStream(save);
  } catch (FileNotFoundException e1) {
   e1.printStackTrace();
  }

  CipherOutputStream out = new CipherOutputStream(fileOutputStream,
    encrypt);
  try {
   out.write(new String(text).getBytes());
   out.flush();
   out.close();
   flag = true;
  } catch (FileNotFoundException e) {
  } catch (IOException e) {
  }

  return flag;
 }

}

 

比较我采用的方法与OutLook存储邮件采用的方法,OutLook保存的是未解析的邮件信息,一般是安全的,如果别有用心的人得到后,要去得到邮件内容其实也是件很容易的事情,而我的方法虽然用加密来降低了这种事情发生的可能性,但加解密势必会占用更多计算机资源影响效率,而且会出现一些问题,在后面介绍,不确定我的方法是否合适,但我是这么做的,而其已经做了。

 

存在的问题:

1.无法保存附件:保存邮件的时候只是保存了附件的名称,文件会丢失。如果采用OutLook哪种形式保存邮件,则不会出现这种问题。我想的解决问题的思路大概是这样子的:

a.找到附件的网络地址,看是否支持独立的下载功能,估计可能性很低。但如果支持问题就很简单了。

b.保存邮件的时候同时将附件下载到本地磁盘,以对话框的形式提示用户附件所在地址或者做一个假象,出现保存文件对话框,但其实实质上只是文件的本地磁盘间的拷贝。这个方法是肯定可以实现的,但不确定是否还有更好的方案。

2.人为破坏:如果有人不是想窃取你的信息,而是破坏,直接将文件夹删除或者对文件内容进行修改,就会造成信息丢失,或者在解析的时候无法正确解析的问题。这个问题OutLook也存在,甚至大多数软件都存在,不知道是否该把它称作问题。设计此软件的部分原因就是,避免对源邮件的操作,所以本地信息的删除破坏,不会影响源邮件。如果出现破坏性的删除修改现象,损失的其实只是本地存储的草稿等邮件。也只能是降低损失,要避免的话就比较麻烦了,要让一个文件夹无法删除,文件内容外部程序不得修改,不是一件简单的事情了。

3.肯定还有一个问题存在,刚才一闪而过,现在记不起来了,想起来的时候再说。

 

稍后带来新邮件提示功能的介绍包括声音提示和手机短信提示。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值