现在的位置: 首页 > 综合 > 正文

Applet 数字签名技术完全攻略

2013年09月07日 ⁄ 综合 ⁄ 共 14217字 ⁄ 字号 评论关闭
 

     在这里先对大家说声对不起,毕竟2年前就想写这篇文章,但因为自己太懒惰一直没有写,也是为了给自己留点东西好了,前些日子我老大让我又搞这个东西发现我以前的资料没留,又凭着自己印象从新来过,但发现网上写的东西真的有些肤浅,实在说不过去,毕竟我们是程序员,不是学生了,怎么也点多想些东西哦,于是将自己总结的东西写下来,留给初学者一些启示好了,通过学习一下内容您将具备通过服务器完全访问本地客户端的能力,不在受任何权限的困扰,(很多文章都写需要改 客户端本地的策略文件,其实根本没必要,只要客户端点了俺们的数字签名,俺们可就什么都能干了) ~oo~    

     简单说下 Applet 数字签名是怎么回事: 就是applet 利用 jdk 里的 工具   $JAVA_HOME/bin 下面的 一堆 exe 文件进行 服务器访问本地客户端的安全签名。如果想让客户真的信任你的applet签名,可以花几百大元去 CA 旗下的 versign 公司购买可信任的 签名证书。

     本文主要以Tomcat为中间件,讲述具体签名步骤,其中 $JAVA_HOME 为 jdk 的安装目录、$TOMCAT_HOME为 Tomcat 的安装目录

      实现Applet的签名步骤如下:

      1. 设定环境变量   $JAVA_HOME (方便在windows 系统下的任何一个目录都可以直接 使用     $JAVA_HOME/bin 下的 exe 命令,其中的exe 包括 keytool.exe,jarsigner.exe和HtmlConverter.exe )。

     2. 将 $TOMCAT_HOME 下 webapps 目录的ROOT目录拷贝一份,删除没有用的垃圾东西改成自己的web应用名字。例如 : webapplet  将需要签名的jar 拷贝到 $TOMCAT_HOME/webapps/webapplet  下,在这里需要 注意一点:签名jar 包 就要对 整个 工程 引用涉及到的 jar 包都进行签名,否则少签一个你都运行不起来的!

    3. 建立一个测试的html页面 applet.html

      <APPLET
CODEBASE = "."
CODE = "com.aspire.reportPlatform.webagent.WebAgentApplet.class"
ARCHIVE ="applet.jar"
NAME = "TestApplet"
WIDTH = 400
HEIGHT = 300
HSPACE = 0
VSPACE = 0
ALIGN = middle

</APPLET>

    4.  打开 cmd 命令提示符,在$TOMCAT_HOME/webapps/webapplet  下运行 HtmlConverter

      例如:  F:/appletTomcat/webapps/webapplet>HtmlConverter 

    弹出个窗口,在窗口中输入需要转换的 html文件 例如我刚才写的applet.html,转换完的东西 写jsp 也同样适用的。

    转换完如下所示 :

     <!--"CONVERTED_APPLET"-->
<!-- HTML CONVERTER -->
<object
    classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
    codebase = "http://java.sun.com/update/1.5.0/jinstall-1_5-windows-i586.cab#Version=5,0,0,1"
    WIDTH = 400 HEIGHT = 300 NAME = "TestApplet" ALIGN = middle VSPACE = 0 HSPACE = 0 >
    <PARAM NAME = CODE VALUE = "com.aspire.reportPlatform.webagent.WebAgentApplet.class" >
    <PARAM NAME = CODEBASE VALUE = "." >
    <PARAM NAME = ARCHIVE VALUE = "applet.jar,commons-codec-1.3.jar,commons-httpclient-3.1.jar,commons-logging.jar,dom4j.jar,FlowMetaData.jar,ibatis-2.3.2.715.jar,jgraph.jar,log4j-1.2.9.jar,MetaDataManage.jar,ojdbc14.jar,RDPCommon.jar,swing-layout-1.0.jar,ws-commons-util-1.0.1.jar,xmlrpc-client-3.1.jar,xmlrpc-common-3.1.jar" >
    <PARAM NAME = NAME VALUE = "TestApplet" >
    <param name = "type" value = "application/x-java-applet;version=1.5">
    <param name = "scriptable" value = "false">

    <comment>
 <embed
            type = "application/x-java-applet;version=1.5" /
            CODE = "com.aspire.reportPlatform.webagent.WebAgentApplet.class" /
            JAVA_CODEBASE = "." /
            ARCHIVE = "applet.jar" /
            NAME = "TestApplet" /
            WIDTH = 400 /
            HEIGHT = 300 /
            ALIGN = middle /
            VSPACE = 0 /
            HSPACE = 0
     scriptable = false
     pluginspage = "http://java.sun.com/products/plugin/index.html#download">
     <noembed>
           
            </noembed>
 </embed>
    </comment>
</object>

<!--
<APPLET CODE = "com.aspire.reportPlatform.webagent.WebAgentApplet.class" JAVA_CODEBASE = "." ARCHIVE = "applet.jar" WIDTH = 400 HEIGHT = 300 NAME = "TestApplet" ALIGN = middle VSPACE = 0 HSPACE = 0>

</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->

       这里需要注意一个东西,上面有写 <PARAM NAME = ARCHIVE VALUE = "applet.jar..  那块,正常转换完了 只会写到 applet.jar , 后面是我直接把 applet 需要引用的 jar 包直接加上去的,再次重复提醒 : 在这里也要把 需要签名关联的所有jar 包都写上去,否则前功尽弃!

    6. 为了省事自己写个bat文件玩,来进行签名,例如我写的 applet.bat

       内容如下:       

keytool -genkey -keystore pepper.store -alias pepper   
keytool -export -keystore pepper.store -alias pepper -file pepper.cert   
jarsigner -keystore pepper.store applet.jar pepper
jarsigner -keystore pepper.store commons-codec-1.3.jar pepper
jarsigner -keystore pepper.store commons-httpclient-3.1.jar pepper
jarsigner -keystore pepper.store commons-logging.jar pepper
jarsigner -keystore pepper.store dom4j.jar pepper
jarsigner -keystore pepper.store FlowMetaData.jar pepper
jarsigner -keystore pepper.store ibatis-2.3.2.715.jar pepper
jarsigner -keystore pepper.store jgraph.jar pepper
jarsigner -keystore pepper.store log4j-1.2.9.jar pepper
jarsigner -keystore pepper.store MetaDataManage.jar pepper
jarsigner -keystore pepper.store ojdbc14.jar pepper
jarsigner -keystore pepper.store RDPCommon.jar pepper
jarsigner -keystore pepper.store swing-layout-1.0.jar pepper
jarsigner -keystore pepper.store ws-commons-util-1.0.1.jar pepper
jarsigner -keystore pepper.store xmlrpc-client-3.1.jar pepper
jarsigner -keystore pepper.store xmlrpc-common-3.1.jar pepper

 

讲解下 里面的意思 : 

     keytool -genkey -keystore pepper.store -alias pepper      #创建pepper.store 密钥库文件,这个密钥库的别名为  pepper 

    输入上面那段话后,会提示输入密码 jdk 默认为  changeit ,这个密码可以修改,如何修改请到网上查下就好,我记不清列,但建议不改,因为有时因为改了密码 jdk1.4 会离奇的不好用。。。

      密码输完 ,就输入些对应的 一些签名信息,

   F:/appletTomcat/webapps/applet>keytool -genkey -keystore pepper.store -alias pepper
输入keystore密码:  changeit
您的名字与姓氏是什么?
  [Unknown]:  LEe
您的组织单位名称是什么?
  [Unknown]:  aspire
您的组织名称是什么?
  [Unknown]:  aspire
您所在的城市或区域名称是什么?
  [Unknown]:  sz
您所在的州或省份名称是什么?
  [Unknown]:  gd
该单位的两字母国家代码是什么
  [Unknown]:  cn
CN=LEe, OU=aspire, O=aspire, L=sz, ST=gd, C=cn 正确吗?
  [否]:  y

输入<pepper>的主密码
        (如果和 keystore 密码相同,按回车):

输入密码库导出证书的密码,为了偷懒上面 那个 我直接 按 回车列。。。

keytool -export -keystore pepper.store -alias pepper -file pepper.cert   根据生成的密钥库导出 pepper.cert  证书,输入密码 changeit , 说一句 这块可以 输入 上步你自己设定 密码库导出证书的密码(如果不是 changeit)

jarsigner -keystore pepper.store applet.jar pepper 为  applet.jar  签名,输入 证书密码  我这块可以写 changeit, 下面的 jar 包 都是重复输入这里不多说了,over !   写到大家应该可以玩自己的签名了,我还有个读取文件方面的经验: 那就是本来在 application 里写的好好的东西到了 applet 上就都不好用了,原因是applet 的加载机制就是 把 服务器上签名的jar 包都下载到 客户端的 临时目录里,文名都给改了。。。  这个临时目录例如我的 :  C:/Documents and Settings/x_lixin_a/Application Data/Sun/Java/Deployment/cache/javapi/v1.0/jar 

所以我在搞读文件的东西都把 配置文件下载到了客户端本地,例如下载到 

  System.getProperty("java.io.tmpdir")    的目录下面,到这里去读就不会出问题列,日志有时也会出问题,建议直接写 ***.log ,这样在运行时会把 生成的日志文件 扔到桌面,其实还是不提倡有日志,毕竟用户看见这个东西不爽。。。

顺便把俺写的 applet 让大家看看吧,

思路 : 1 .  将需要读取的 配置文件下载到本地。 2 .  运行 main 类,跑application 。 
测试 :  在  ie 中输入 http://localhost:8080/webapplet          看到有 applet 弹出一个框点击运行就成,顺便提一句: 查看错误可以注意下右下角任务栏出现的大茶壶图标,        运行applet 都会启动这个东西,点击右键看到有 打开主控制台的选项,点这个选项,弹出一个对话框,这个对话框        就可以查看你的 签名 哪里出问题了,用 System.out.println() 都可以打到这个控制台上,但建议先在本地的        Eclipse 工程里 运行通过在拿到上面试。   后记 :  写到这里大家应该都会知道怎么实现 applet 数字签名了,如果有什么疑问可以直接在 csdn抓我,或者发送邮件到   lixin_0411@126.com,  希望有log 日志那块配置 更好解决方案的一定要告诉我撒,互相交流下哇,觉得我写的这篇文章还可以  朋友希望能帮我顶起来,希望一年以后我将不会在看到网上写的那篇垃圾文章(现在那篇文章写的哪都是,根本不能解决问题!)   ~oo~

代码如下: 

package com.aspire.reportPlatform.webagent;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Container;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.swing.JApplet;

import com.aspire.rdp.flowdesinger.LogonDialog;



public class WebAgentApplet extends JApplet {

	public static Applet m_runningApplet = null;

	protected char m_osPrefix;

//	private OctetSeqHolder resp = null;

	private Container contentPane = null;

	public static String agentID;
	
	private static Long agentLongID;

	//	private static final String DLLFOLDERPATH= System.getProperty("user.dir")
	// ;

	//	private static final String
	// DLLFOLDERPATH=System.getProperty("java.home")+File.separator+"lib"+File.separator+"ext";

	private static final String DLLFOLDERPATH = System.getProperty("java.home")
			+ File.separator + "bin";
	
	String TEMP_DIR = System.getProperty("java.io.tmpdir");

	private int result = 1;

	private int count = 0;

	public static String certerIP = null;

	private String nickname = null;

	public static String serverFullAddress;

	/**
     * @throws java.lang.AbstractMethodError
     */
    public void init() {

	    certerIP = getParameter("centerAddress");

		certerIP = new String("192.168.168.111");

		System.err.println("centerIP is" + certerIP);
		System.out.println(" user.dir = "+ System.getProperty("user.dir"));
		nickname = getParameter("nickname");
		serverFullAddress = String.valueOf(getCodeBase());
		m_osPrefix = System.getProperty("os.name").toLowerCase().charAt(0);
//		installLibraries();
		
		DirectoryVO directoryVOArray[] = createDirectories(); 
		
		for(int i=0;i< directoryVOArray.length;i++) {
			installConfigResources(directoryVOArray[i]);
		}
		
		
		drawPane();
		
		LogonDialog logonDialog = new LogonDialog();
		logonDialog.setVisible(true);

		try {
//			        add(panel);
			if (m_runningApplet != null) {
				StatusPanel.getStatusPanelInstance().setStatus((byte) 11);
			} else {
				m_runningApplet = this;
//					webAgent = new WebAgent();
//					initializeCommunication(webAgent);
				StatusPanel.getStatusPanelInstance()
				.setStatus((byte) 11);
//					if (result == 0) {
//						StatusPanel.getStatusPanelInstance()
//								.setStatus((byte) 0);
//					} else {
//						StatusPanel.getStatusPanelInstance()
//								.setStatus((byte) 8);
//					}
					//					 heartbeatInfo = new HeartbeatInfo();
					//		        new Thread(heartbeatInfo).start();
//					webAgent.initialize(webAgent, this);
//					sendHeartInfo();		
			}
		} catch (Exception _ex) {
			//			LogFile.getInstance().print(0, "WebAgentApplet.init()",
			//					" Applet initial Failed !");
			//			_ex.printStackTrace();
			StatusPanel.getStatusPanelInstance().setStatus((byte) 8);
			_ex.printStackTrace();
//			destroy();
		}
	}
    
    private DirectoryVO[] createDirectories() {
    	DirectoryVO[] directoryVOArray = new DirectoryVO[3];
    	DirectoryVO  directoryVO =  new DirectoryVO();
    	
    	String config = TEMP_DIR+"rdp";
		
		File configFile=new File(config);
		if(!configFile.exists()) {
			configFile.mkdir();
		}
		String plugins = config + File.separator + "plugins";
		File pluginsFile= new File(plugins);
		if(!pluginsFile.exists()) {
			pluginsFile.mkdir();
		}
		String email = plugins + File.separator + "email";
		File emailFile= new File(email);
		if(!emailFile.exists()) {
			emailFile.mkdir();
		}
		
		directoryVO.setPathName(email);
		directoryVO.setZipName("emailPlugins.zip");
		directoryVOArray[0] = directoryVO;
		String images = config + File.separator + "images";
		File imagesFile = new File(images);
		if(!imagesFile.exists()) {
			imagesFile.mkdir();
		}
		
		String cfg = config + File.separator + "cfg";
		File cfgFile = new File(cfg);
		if(!cfgFile.exists()) {
			cfgFile.mkdir();
		}
		DirectoryVO  directoryVO1 =  new DirectoryVO();
		directoryVO1.setZipName("images.zip");
		directoryVO1.setPathName(images);
		directoryVOArray[1] = directoryVO1;
		
		DirectoryVO  directoryVO2 =  new DirectoryVO();
		directoryVO2.setZipName("cfg.zip");
		directoryVO2.setPathName(cfg);
		directoryVOArray[2] = directoryVO2;
		
    	return directoryVOArray;
    }
        
    private void installConfigResources(DirectoryVO directoryVO){
    	String archivePath = String.valueOf(getCodeBase()) + "native" + "/" + directoryVO.getZipName();
    	System.out.println("  archivePath = " + archivePath);
		ZipInputStream zis = null;
		ZipEntry entry = null;
		URLConnection con = null;
		
			
		try {
			con = (new URL(archivePath)).openConnection();
			con.setUseCaches(false);
			con.connect();
			zis = new ZipInputStream(con.getInputStream());
			while ((entry = zis.getNextEntry()) != null){
				installConfigResource(zis, entry.getName(),directoryVO.getPathName());
			}
		} catch (IOException ioe) {
			StatusPanel.getStatusPanelInstance().setStatus((byte) 8);
			ioe.printStackTrace();
			//			LogFile.getInstance().print(0,
			// "WebAgentApplet.installLibraries()",
			//					"install have IOException ");
		}catch(Exception e){
		    e.printStackTrace();	
		}finally {
			con = null;
			try {
				zis.close();
			} catch (IOException e) {
				// TODO 自动生成 catch 块
				e.printStackTrace();
			}
		}
    }
    
    
    private void installConfigResource(ZipInputStream archive, String configResourceName,String path){
    	BufferedOutputStream out = null;
		byte buffer[] = new byte[1024];
		int count = 0;
		String configFullPathName = path + File.separator + configResourceName;
		
		try {
			out = new BufferedOutputStream(
					new FileOutputStream(configFullPathName));
			while ((count = archive.read(buffer)) > 0)
				out.write(buffer, 0, count);
			out.close();
		} catch (IOException e) {
			
			e.printStackTrace();
		}catch(Exception e){
		    e.printStackTrace();	
		}finally{
			try {
				out.close();
			} catch (IOException e1) {
				// TODO 自动生成 catch 块
				e1.printStackTrace();
			}
		}

		
    }
    


	public void drawPane() {
		contentPane = getContentPane();
		contentPane.setBackground(Color.white);
		contentPane.add(StatusPanel.getStatusPanelInstance());
	}

	public void destroy() {

		try {
			if (m_runningApplet == this) {
//				webAgent.testManagerModule.close();
//				StatusControl.getStatusControlInstance().notifyToCenter(StatusControlModuleConstant.AGENT_DOWN_SUCCESS,agentLongID);
//				appletCommunicateModule.stop();

			}
		} catch (Exception e) {
			//			LogFile.getInstance().print(0, "WebAgentApplet.destroy()",
			//					"UnknownHostException : cannot destory applet ");
             
			e.printStackTrace();
		} finally {
			System.exit(0);
			System.err.println("in applet close !!!!");
		}

	}
	
	private void installLibraries() {

		String archivePath = String.valueOf(getCodeBase()) + "native";
		System.err.println(getCodeBase());
    	ZipInputStream zis = null;
		ZipEntry entry = null;
		URLConnection con = null;
		String archiveName;
		switch (m_osPrefix) {
		case 119: // &apos;w&apos;
			archiveName = "winLib.zip";
			break;

		case 108: // &apos;l&apos;
			archiveName = "linuxLib.zip";
			break;

		case 115: // &apos;s&apos;
			archiveName = "solarisLib.zip";
			break;

		default:
			archiveName = "winLib.zip";
			break;
		}
		try {
			con = (new URL(archivePath + "/" + archiveName)).openConnection();
			con.setUseCaches(false);
			con.connect();
			zis = new ZipInputStream(con.getInputStream());
			while ((entry = zis.getNextEntry()) != null){
				installLibrary(zis, entry.getName());
			}
		} catch (IOException ioe) {
			StatusPanel.getStatusPanelInstance().setStatus((byte) 8);
			ioe.printStackTrace();
			//			LogFile.getInstance().print(0,
			// "WebAgentApplet.installLibraries()",
			//					"install have IOException ");
		}catch(Exception e){
		    e.printStackTrace();	
		}finally {
			con = null;
			try {
				zis.close();
			} catch (IOException e) {
				// TODO 自动生成 catch 块
				e.printStackTrace();
			}
		}
	}

	private void installLibrary(ZipInputStream archive, String dllName) {
		BufferedOutputStream out = null;
		byte buffer[] = new byte[1024];
		int count = 0;
		String dllFullPathName = DLLFOLDERPATH + File.separator + dllName;
		System.out.println("  dllFullPathName = " + dllFullPathName);
		try {
			out = new BufferedOutputStream(
					new FileOutputStream(dllFullPathName));
			while ((count = archive.read(buffer)) > 0)
				out.write(buffer, 0, count);
			out.close();
			//          if(m_osPrefix != &apos;w&apos;)
			//              CommandLineUtility.runCommand("chmod 0775 " + dllFullPathName);
		} catch (IOException e) {
			
			e.printStackTrace();
			//			LogFile.getInstance().print(0, "WebAgentApplet.installLibrary()",
			//					"install single Library failed ");

			//          exitDueToException(e, "copying a native library file into JRE
			// directory");
		}catch(Exception e){
		    e.printStackTrace();	
		}finally{
			try {
				out.close();
			} catch (IOException e1) {
				// TODO 自动生成 catch 块
				e1.printStackTrace();
			}
		}
	}

	//	private void installLogFile(){
	//		try {
	//			String
	// logProperties=System.getProperty("java.home")+File.separator+"bin"+File.separator+"log4j.properties";
	//			File f=new File(logProperties);
	//			f.createNewFile();
	//				FileOutputStream fopt=new FileOutputStream(f);
	//				String firstParagraph=new String("##LOGGERS##/r/n#define a logger named
	// SEAMISLogger/r/nlog4j.rootLogger=INFO,file/r/n/r/n");
	//				fopt.write(firstParagraph.getBytes());
	//				String senondParagraph=new String("##APPENDERS##/r/n#define an appender
	// named file,which is set to be a
	// RollingFileAppender/r/nlog4j.appender.file=org.apache.log4j.RollingFileAppender/r/n"+"log4j.appender.file.File="+System.getProperty("java.home")+File.separator+"bin"+File.separator+"agentlog.txt"+"/r/n/r/n");
	//	        	fopt.write(senondParagraph.getBytes());
	//				String thirdParagraph=new String("##LAYOUTS##/r/n#assign a SimpleLayout
	// to file
	// appender/r/nlog4j.appender.file.layout=org.apache.log4j.SimpleLayout/r/n");
	//				fopt.write(thirdParagraph.getBytes());
	//				fopt.close();
	//			} catch (FileNotFoundException e) {
	//				// TODO 自动生成 catch 块
	//				e.printStackTrace();
	//			} catch (IOException e) {
	//				// TODO 自动生成 catch 块
	//				e.printStackTrace();
	//			}
	//	}
}

抱歉!评论已关闭.