??xml version="1.0" encoding="utf-8" standalone="yes"?>
(tng) (tng) (tng) public void doFilter(ServletRequest request, ServletResponse response,
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) FilterChain chain) throws IOException, ServletException {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) HttpServletRequest req = (HttpServletRequest) request;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) int length = req.getContentLength();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) if (length > 0) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(req,length);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) InputStream is = bufferedRequest.getInputStream();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) byte[] content = new byte[length];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int pad = 0;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while(pad < length){
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) pad += is.read(content, pad, length);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)request = bufferedRequest;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) chain.doFilter(request, response); (tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) }
BufferedRequestWrapper .java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class BufferedRequestWrapper extends HttpServletRequestWrapper {
(tng) (tng) (tng) ByteArrayInputStream bais;
(tng) (tng) (tng) BufferedServletInputStream bsis;
(tng) (tng) (tng) byte[] buffer;
(tng) (tng) (tng) public BufferedRequestWrapper(HttpServletRequest req,int length) throws IOException {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) super(req);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // Read InputStream and store its content in a buffer.
(tng) (tng) (tng) (tng) (tng) (tng) (tng) InputStream is = req.getInputStream();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) buffer = new byte[length];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) int pad = 0;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) while(pad < length){
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) pad += is.read(buffer, pad, length);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) }
(tng) (tng) (tng) public ServletInputStream getInputStream() {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // Generate a new InputStream by stored buffer
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) bais = new ByteArrayInputStream(buffer);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // Istantiate a subclass of ServletInputStream
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // (Only ServletInputStream or subclasses of it are accepted by the
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // servlet engine!)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) bsis = new BufferedServletInputStream(bais);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) } catch (Exception ex) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ex.printStackTrace();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) } finally {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return bsis;
(tng) (tng) (tng) }
}
BufferedServletInputStream .java
import java.io.*;
import javax.servlet.ServletInputStream;
/*
(tng)Subclass of ServletInputStream needed by the servlet engine.
(tng)All inputStream methods are wrapped and are delegated to
(tng)the ByteArrayInputStream (obtained as constructor parameter)!
(tng)*/
public class BufferedServletInputStream extends ServletInputStream {
(tng) (tng) (tng) ByteArrayInputStream bais;
(tng) (tng) (tng) public BufferedServletInputStream(ByteArrayInputStream bais) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) this.bais = bais;
(tng) (tng) (tng) }
(tng) (tng) (tng) public int available() {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return bais.available();
(tng) (tng) (tng) }
(tng) (tng) (tng) public int read() {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return bais.read();
(tng) (tng) (tng) }
(tng) (tng) (tng) public int read(byte[] buf, int off, int len) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return bais.read(buf, off, len);
(tng) (tng) (tng) }
}
(tng) (tng) (tng) // Fill the message
(tng) (tng) (tng) messageBodyPart.setText(body);
(tng) (tng) (tng) mp.addBodyPart(messageBodyPart);
(tng) (tng) (tng) (tng) (tng) /*发送附?/
(tng) (tng) (tng) (tng) if (file != null && file.length > 0) {
(tng) (tng) (tng) (tng) (tng) (tng) //利用枚D器方便的遍历集合
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) MimeBodyPart mbp = new MimeBodyPart(); (tng)
// (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) File fileTmp = null;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //得到数据?br />// (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) FileDataSource fds = new FileDataSource(fileTmp);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //得到附g本nq至入BodyPart
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(file,"application/octet-stream")));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //得到文g名同栯入BodyPart
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) mbp.setFileName(MimeUtility.encodeWord(fileName,"GB2312",null));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) mp.addBodyPart(mbp);
(tng) (tng) (tng) (tng) }
(tng) (tng) (tng)
(tng) (tng) (tng) //Multipart加入C?br /> (tng) (tng) (tng) msg.setContent(mp);
(tng) (tng) (tng) msg.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
(tng) (tng) (tng) msg.setSubject(subject);
(tng) (tng) (tng) msg.setHeader("X-Mailer", "personal Email Sender");
(tng) (tng) (tng) msg.setSentDate(new Date());
(tng) (tng) (tng) Transport transport = session.getTransport("smtp");
(tng) (tng) (tng) //d认证信息
(tng) (tng) (tng) transport.connect(Constants.mailhost, Constants.user, Constants.pwd);
(tng) (tng) (tng) transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
(tng) (tng) (tng) transport.close();
(tng) (tng) (tng) return true;
(tng) }
import java.io.*;
import javax.activation.*;
public class ByteArrayDataSource implements DataSource {
(tng) (tng) (tng) /** * Data to write. */
(tng) (tng) (tng) private byte[] _data;
(tng) (tng) (tng) /** * Content-Type. */
(tng) (tng) (tng) private String _type;
(tng) (tng) (tng) /* Create a datasource from an input stream */
(tng) (tng) (tng) public ByteArrayDataSource(InputStream is, String type) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) _type = type;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ByteArrayOutputStream os = new ByteArrayOutputStream();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int ch;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // XXX : must be made more efficient by
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // doing buffered reads, rather than one byte reads
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while ((ch = is.read()) != -1)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) os.write(ch);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) _data = os.toByteArray();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) } catch (IOException ioe) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) }
(tng) (tng) (tng) /* Create a datasource from a byte array */
(tng) (tng) (tng) public ByteArrayDataSource(byte[] data, String type) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) _data = data;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) _type = type;
(tng) (tng) (tng) }
(tng) (tng) (tng) /* Create a datasource from a String */
(tng) (tng) (tng) public ByteArrayDataSource(String data, String type) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // Assumption that the string contains only ascii
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // characters ! Else just pass in a charset into this
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) // constructor and use it in getBytes()
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) _data = data.getBytes("iso-8859-1");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) } catch (UnsupportedEncodingException uee) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) _type = type;
(tng) (tng) (tng) }
(tng) (tng) (tng) public InputStream getInputStream() throws IOException {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) if (_data == null)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) throw new IOException("no data");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return new ByteArrayInputStream(_data);
(tng) (tng) (tng) }
(tng) (tng) (tng) public OutputStream getOutputStream() throws IOException {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) throw new IOException("cannot do this");
(tng) (tng) (tng) }
(tng) (tng) (tng) public String getContentType() {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return _type;
(tng) (tng) (tng) }
(tng) (tng) (tng) public String getName() {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) return "dummy";
(tng) (tng) (tng) }
}
扑և内存泄漏另一Ҏ(gu)
E序有内存泄漏的W一个迹象通常是它抛出一?OutOfMemoryError
Q或者因为频J的垃圾攉而表现出p糕的性能。幸q的是,垃圾攉可以提供能够用来诊断内存泄漏的大量信息。如果以 -verbose:gc
或?-Xloggc
选项调用 JVMQ那么每?GC q行时在控制C或者日志文件中?x)打印出一个诊断信息,包括它所p的时间、当前堆使用情况以及(qing)恢复?jin)多内存。记?GC 使用情况q不hq扰性,因此如果需要分析内存问题或者调优垃圾收集器Q在生环境中默认启?GC 日志是值得的?
有工具可以利?GC 日志输出q以囑Ş方式它昄出来QJTune 是q样的一U工P请参?参考资?/FONT>Q。观?GC 之后堆大的图,可以看到E序内存?sh)用的趋ѝ对于大多数E序来说Q可以将内存?sh)用分?f)两部分:(x)baseline 使用?current load 使用。对于服务器应用E序Qbaseline 使用是应用E序在没有Q何负荗但是已l准备好接受h时的内存?sh)用Qcurrent load 使用是在处理hq程中用的、但是在h处理完成后会(x)释放的内存。只要负荷大体上是恒定的Q应用程序通常?x)很快达C个稳定的内存?sh)用水^。如果在应用E序已经完成?jin)其初始化ƈ且负h有增加的情况下,内存?sh)用持?hu)增加Q那么程序就可能在处理前面的h时保留了(jin)生成的对象?
?1 昄 GC 之后应用E序堆大随着旉的变化图。上升趋势是存在内存泄漏的警CZ受(在真实的应用E序中,坡度不会(x)q么大,但是在收集了(jin)_长时间的 GC 数据后,上升势通常?x)表现得很明显。)(j)
信有了(jin)内存泄漏后,下一步就是找出哪U对象造成?jin)这个问题。所有内存分析器都可以生成按照对象类q行分解的堆快照。有一些很好的商业堆分析工P但是扑և内存泄漏不一定要花钱买这些工?—?内置?hprof
工具也可完成q项工作。要使用 hprof
q让它跟t内存(sh)用,需要以 -Xrunhprof:heap=sites
选项调用 JVM?
清单 3 昄分解?jin)应用程序内存?sh)用的 hprof
输出的相关部分。(hprof
工具在应用程序退出时Q或者用 kill -3
或在 Windows 中按 Ctrl+Break 时生成用分解。)(j)注意两次快照相比Q?CODE>Map.Entry?CODE>Task ?int[]
对象有了(jin)显著增加?
请参?清单 3?/P>
清单 4 展示?hprof
输出的另一部分Q给Z(jin) Map.Entry
对象的分配点的调用堆栈信息。这个输出告诉我们哪些调用链生成?Map.Entry
对象Qƈ带有一些程序分析,扑և内存泄漏来源一般来说是相当Ҏ(gu)的?
|
问题的关键在于用aCC~译时的参数. |
1. 你要传送的文g装在DataHandler中,然后DataHandler对象或DataHandler数组Q多个文件传送的时候)(j)作ؓ(f)客户端调用函数的参数Q从客户端上传文件到服务器)(j)Axis服务的返回类型(从服务器端下载文件到客户端)(j)q行传输?/P>
2. q有一U方式是直接修改soap信封的内容,附件信息加到soap信封中发送?/P>
q里我们只讨论第一U方法,因ؓ(f)它实现v来非常简单。关于第二种Ҏ(gu)在Axis包的webapps/attachments/TestRf.java中有详细的原码可以参考?/P>
下面的例子是把文件从服务器端下蝲到客L(fng)Q?/P>
1.服务端程序:(x)
假设传输多个文gQ在服务器端文件取出来Qƈ文件封装在DataHandler数组中?BR>代码如下Q?/P>
DataHandler[] ret = new DataHandler[totalFileNum];
... ...
java.io.File myFile = new java.io.File(filePath);
if(myFile.isFile() && myFile.canRead())
{
String fname = myFile.getAbsoluteFile().getCanonicalPath();
DataHandler[0] = new DataHandler(new FileDataSource(fname));
}
... ...
return ret;
上面的代码将所有的文g装在了(jin)DataHandler数组中,q返回?/P>
2. 客户端的讉KQ?/P>
代码如下Q?BR> Service service = new Service();
Call call = (Call) service.createCall();
call.registerTypeMapping(DataHandler.class, qnameAttachment, JAFDataHandlerSerializerFactory.class,JAFDataHandlerDeserializerFactory.class); //为附Ӟ即DataHandlerc)(j)创徏序列化生成器
call.addParameter("source", XMLType.XSD_STRING ,ParameterMode.IN); //讄服务调用Ҏ(gu)的传入参数类?BR> call.setReturnType(XMLType.SOAP_ARRAY); //讄调用服务Ҏ(gu)的返回类型,׃q回的是DataHandler数组Q所以设|ؓ(f)SOAP_ARRAYcd
javax.activation.DataHandler[] ret = (javax.activation.DataHandler[])call.invoke(new Object[]{null}); //调用Ҏ(gu)
for (i = 0; i < ret.length; ++i)
{
DataHandler recDH = ret[i];
java.io.File receivedFile = new java.io.File(recDH.getName()); //文g生成
}
3. 服务的部|Ԍ(x)
注意Q你要在部v的时候,定义DataHandler的序列化生成器?/P>
<parameter name="className" value="samples.att_STC.att_STC_Server"/>
<parameter name="allowedMethods" value="echoDir"/>
<typeMapping deserializer="org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory"
languageSpecificType="java:javax.activation.DataHandler" qname="ns1:DataHandler"
serializer="org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</service>
</deployment>
q行java org.apache.axis.client.AdminClient %* deploy.wsddQ部|服务?/P>
主题: 使用Java实现CA(? 前面几篇文章已经把如何用Java实现一个CA基本上讲完了(jin).但是他们都有一个特?是用户的信息都是在现场获取?不能做申请和{֏相分?今天我们要讲q的是PKCS#10证书h文g.它的作用是可以使申请和{֏相分? PKCS#10证书hl构中的主要信息包含?jin)被{֏?证书甌?的主体名U?DN)和他的公?因此一个CA在获取到一个PKCS#10证书h?可以从中获取到M和签发证书有关的信息,然后用它自己的私钥签发证? 使用BC Provider在Java中构造一个证书请求格式的对象调用其构造函数即?q个函数如下: PKCS10CertificationRequest(java.lang.String signatureAlgorithm, X509Name subject, java.security.PublicKey key, ASN1Set attributes, java.security.PrivateKey signingKey) 它的参数是自{法,证书甌者的DN,证书甌者的公钥,额外的属性集(是要申L(fng)证书的扩展信?,甌证书者的U钥.甌证书者的U钥仅仅是用来进行一下自{,q不出现在证书请求中,需要自{的目的是保证该公钥确实ؓ(f)甌者所? 调用该对象的getEncoded()Ҏ(gu)可以其q行DER~码,然后储存h,该对象还有另一个构造函? 利用证书hl构q行证书{֏的代码如?q里假设CSR是一个已l获取出来的PKCS10CertificationRequestl构: PublicKey SubjectPublicKey = CSR.getPublicKey(); q样,甌者的MDN,甌者的公钥,甌者希望在证书扩展信息中填写的属性都得到?剩下的事情就和用户在现场输入时一样了(jin),其它的信息一般是甌者不能决定的.另外证书h格式中有一样信息没有明给出来,那就是证书的有效?q个应该单独询问用户,或者用其它的方法保存v?
PKCS10CertificationRequest(byte[] bytes)
q个构造函数的作用是直接从储存的DER~码中把q个对象q原出来.
CertificationRequestInfo CSRInfo = CSR.getCertificationRequestInfo();
X509Name SubjectDN = CSRInfo.getSubject();
ASN1Set Attributes = CSRInfo.getAttributes();
[q回剙]
2004-05-28 16:46:12
主题: 使用Java实现CA(? 前几ơ我已经基本上把如何做CA所需要的基础知识讲得差不多了(jin),今天直接讲如何用JavaE序来实C个CA应该׃是什么太困难的事情了(jin). 要做CA,W一步要准备好自q证书和私?U钥如何从文仉面读取出来前面已l讲q了(jin).从文件系l中d证书的代码如? CertificateFactory certCF = CertificateFactory.getInstance("X.509"); q里cerBIS是一个InputStreamcd的对?例如一个标准的X509v3格式的证书文件所形成的输入流. W二步就是从用户那里获取输入,然后构造主体名U结构DN,如何构造DN上次已经说过?如何从用户那里获取输?q个不在本文讨论范围之内. 下一步就是获取用L(fng)公钥,好和他所需要的证书对应h.也有不少CA的做法就是在q里替用L(fng)场生成一对密钥对,然后把公钥放到证书中{֏l用?q个应该看实际需要选择合适的方式. 现在一切信息都已经准备好了(jin),可以{֏证书?下面的代码说明了(jin)q个q程: //构造一个证书生成器对象 X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); // 从CA的证书中获取{֏者的M名称(DN)
X509Certificate caCert = certCF.generateCertificate(certBIS);
// q里有一点小技?我们要把JCE中定义的
// 用来表示DN的对?FONT face=新宋(hu)?size=2>X500Principal
// BC Provider中的相应的对?FONT face=新宋(hu)?size=2>X509Name
// 先从CA的证书中d出CA的DNq行DER~码
DERInputStream dnStream =
new DERInputStream(
new ByteArrayInputStream(
caCert.getSubjectX500Principal().
getEncoded()));
// 马上又从~码后的字节中dDER~码对象
DERConstructedSequence dnSequence =
(DERConstructedSequence)dnStream.readObject();
// 利用d出来的DER~码对象创徏X509Name
// 对象,q设|ؓ(f)证书生成器中?{֏者DN"
certGen.setIssuerDN(new X509Name(dnSequence));
// 讄好证书生成器中的"接收方DN"
certGen.setSubjectDN(subjectDN);
// 讄好一些扩展字D?包括{֏者和
// 接收者的公钥标识
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
createSubjectKeyId(keyToCertify));
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
createAuthorityKeyId(caCert.getPublicKey()));
// 讄证书的有效期和序列号
certGen.setNotBefore(startDate);
certGen.setNotAfter(endDate);
certGen.setSerialNumber(serialNumber);
// 讄{法,本例中用MD5hash后RSA
// {,q且讄好主体的公钥
certGen.setSignatureAlgorithm("MD5withRSA");
certGen.setPublicKey(keyToCertify);
// 如果以上一切都正常地话,可以生成证书了(jin)
X509Certificate cert = null;
cert = certGen.generateX509Certificate(caPrivateKey);
q里是上面用到的生成{֏者公钥标识的函数:
protected AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pubKey)
{
AuthorityKeyIdentifier authKeyId = null;
try
{
ByteArrayInputStream bIn = new ByteArrayInputStream(pubKey.getEncoded());
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
(DERConstructedSequence)new DERInputStream(bIn).readObject());
authKeyId = new AuthorityKeyIdentifier(info);
}
catch (IOException e)
{
System.err.println("Error generating SubjectKeyIdentifier: " +
e.toString());
System.exit(1);
}
return authKeyId;
}
生成M公钥标识的函数和上面的类?把AuthorityKeyIdentifier替换成SubjectKeyIdentifier可以了(jin).
q里要注意的?CA的公钥也是在一份证书里,q种证书的特Ҏ(gu){֏者DN和接收者DN一?也就是说,q种证书是CA自己l自己颁发的证书,也就?自签名证?,它上面的公钥是CA自n的公?用来{的私钥就是该公钥对应的私?一般每个CA都要有这么一份证?除非该CA不是根CA,卛_的权威性不是由它自p?而是由它的上UCA证明.但是,最后d要有一个根CA,它ؓ(f)各个安全应用E序的用h信赖.
到这里我们已l把CA最基本的功能如何用Java实现讲完?下一ơ讲如何从PKCS#10格式证书h文g中读取出用户信息,然后直接{֏公钥.
2004-05-27 15:34:59
主题: 使用Java实现CA(? 昨天本来快写完了(jin),l果不小?j)按?tab"?然后向按退格键,l果退到前一个页面了(jin),然后全部都白写了(jin),不爽.只好今天重新写了(jin). 上次我们讲到如何生成密钥?以及(qing)如何诸如公?U钥,证书{这一cd全对象在文gpȝ和内存(sh)间来回{?q些是准备开CA的基本功,今天我们讲一下CA的基本原理以?qing)如何用主体名U结构DN(Distinguish Name)来表C每一个证书中的主? 一份证书就是一个权威机构对一个主体的w䆾的确认的证明.即一份证书表CZ个权威机构确认了(jin)一个主体就是它自己,而不是其它的冒名替?M可以是一个个?也可以不?例如,在需要安全服务的时?需要ؓ(f)一台网站的服务器颁发证?q种证书的主体就是一台服务器.{v证书的权威机构就叫做CA,该权威机构本w也是一个主?权威机构通过对包含有待认证的M的一pd信息的待{证书"(TBS,to be signed)q行数字{来表C机构对它的认?一份包含了(jin)待认证的M的相关信息的TBS再加上CA使用自己的私钥进行签名生的字节放在一?构成了(jin)一份标准的X509证书. 一个TBS中包含了(jin)以下q些主要信息: 证书的版?通常?(X509v3) 证书的序列号,RFC3280中规?每个CA必须保它颁发的每一份证书的序列号都是唯一?q且序列号只能用非负整? {֏?CA)的主体名U?一个DN对象. 证书的有效期,表示Ҏ(gu)是两个时间?表示?jin)该证书从何时开始生?何时开始作? 待认证的M的主体名U?也是一个DN对象. 待认证的M的公?M安全应用在确认完证书的有效性后,可以开始用该M的公钥与之进行安全通信. 如果是X509v3证书,即版本号?的话,后面q有一个证书扩展信息字D?可以在证书里面添加一些其它的信息. 下面我们来看一下表CZ体的M名称l构:DN.q个l就构是一个属性的集合.每个属性有属性名U和属性?它的作用是用来表示"我是?,也就是说,q个证书到底是谁颁发l谁?q个证书对应的公钥是谁拥有的. 通常使用一个字W串来表CDNl构,q种字符串说明了(jin)q种l构中的各个属性的cd和? C=CN;S=BeiJing;L=BeiJing;O=PKU;OU=ICST;CN=wolfenstein q里C是国家和地区代码,S和L都是地区代码,S相当于省或者州q样的?L相当于城?jng)?O是组l机构名U?OU是次U组l机构名U?CN是主体的通用?common name).在这?C,S,L{等属性的cd都是相对固定?例如C一般就是用来表C国家和地区代码,在DNl构中还可以d一些其它类型的信息,一般也都是?xxx=xxx"q样来表C的. 下面我们来说明如何在Java语言中构造出一个主体名U对? BC Provider中用X509Name对象来表CDN,构造一个X509Name的步骤大体如? 先构造两个vector对象,用来表示属性名U和属性? Vector oids = new Vector(); 然后在oidsq个用来表示属性名U的vector对象中将属性名UC个一个添加进? oids.addElement(X509Name.C); ...... oids.addElement(X509Name.CN); X509Name对象里面有若q常?例如上面的X509Name.C.q有X509Name.ST{等,都可以和上面丄例子对应h. 然后属性值添加到attributes对象? attributes.addElement("CN"); ...... attributes.addElement("Wolfenstein"); 最后就可以构造出一个X509Name对象: X509Name SubjectDN = new X509Name(oids, attributes); q样,我们的主体名U结构就立h? 下次我们可以讲关键的部分了(jin),那就是如何用JavaE序完成CA最重要的功?{v证书.
Vector attributes = new Vector();
[q回剙]
2004-05-25 21:23:52
主题: 使用Java实现CA(一) 通过我昨天的文章大家应该已经清楚?用Java写信息安全方面的E序需要做的准备工?好了(jin),现在假设你已l是一个对Java语言本n比较熟?zhn)?能够用Java写一些程序的?q且q些该下载的jar包已l下载好?可以正式开工了(jin). 在所有的此类E序的开?无论是在cȝ构造函C也好,在初始化函数中也?,都要先来上这么一?Security.addProvider(new BouncyCastleProvider());BouncyCaslte的Providerd到系l中,q样以后pȝ在运行相关程序的时候调用的是q个Provider中的加密法. 然后我们可以开始开CA?首先,作ؓ(f)一个CA要有自己的一对公钥和U钥,我们先要生成q么一?使用KeyPairGenerator对象可以了(jin),调用KeyPairGenerator.getInstanceҎ(gu)可以Ҏ(gu)要生成的密钥cd来生一个合适的实例,例如常用的RSA,DSA{?然后调用该对象的initializeҎ(gu)和generateKeyPairҎ(gu)可以生一个KeyPair对象?然后调用KeyPair对象中的相应Ҏ(gu)可以获取生成的密钥对中的公钥和U钥? 有了(jin)公钥和私钥对以后,下面的一个很现实问题是如何把它们储存v?通常我们要对q些安全对象,如公?U钥,证书{先q行~码.~码的目的是Z(jin)把结构复杂的安全对象变成字节以便存储和d,如DER~码.另外,通常q把DER~码后的字节再ơ进行base64~码,以便使字节流中所有的字节都变成可打印的字? 在Java语言?q些安全对象基本上都有getEncoded()Ҏ(gu).例如: byte[] keyBytes = privateKey.getEncoded(); q样把一个私钥进行了(jin)DER~码后的l果保存C个byte数组中了(jin).然后可以把q个byte数组保存CQ何介质中.如果有必要的?可以使用BC Provider中的Base64~码解码器类q行~码,像q样: byte data[] = Base64.encode(keyBytes); 要从文g中读取私钥则应该q样: PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyData); q里说明一?对RSAU钥q行~码׃(x)自动地按照PKCS8q行.因此d的时候将包含~码的字节数l作为PKCS8EncodedKeySpec对象的构造函数的参数可以生成一个该cd的对?然后创徏一个密钥工厂对象就可以按照要求生成一个RSAU钥?很显然这里的keyData应该是和上面的keyBytes内容相同. Z(jin)提高pȝ的安全?通常U钥在经qDER~码?q(sh)(x)使用一个口令进行加?然后再储存在文gpȝ?在用私钥的时?如果没有正确的口?是无法把U钥q原出来? 保存证书和保存私钥类?Certificate对象中也有一个getEncoded的方? q次pq些.大家应该可以把这些安全对象很熟练C文gpȝ和内存(sh)间来回地折腾?jin)?q对以后实现CA是很重要?下次我会(x)讲一下证书中表示M的方?DN.
KeyFactory kfac = KeyFactory.getInstance("RSA");
privateKey = kfac.generatePrivate(spec);
[q回剙]
2004-05-24 17:23:06
主题: 使用Java开发和信息安全相关的程?/A> q里说的信息安全是相对于pȝ安全而言?它更侧重于加?解密,数字{,验证,证书{等.而系l安全主要侧重于pȝ本n是否有安全漏z?如常见的׃软g设计的不完善而导致的满天飞的~冲区溢出等{? Java语言中负责加密功能的部g是JCE(Java Crypto Extenstion),它用开攑ּ的思想,可以允许用户自己~写加密法的具体实现的模块{?q些东西被称为JCE Provider,JCE的提供?SUN公司本n提供?jin)一些Provider.不过我推荐用Bouncy Castle的Provider.原因是它实现的加密算法多,q比较新的椭圆曲U?ECC)法都有??A >http://www.bouncycastle.org/
q次先写q么多了(jin),下次开始具体讲把这些东西搞下来后怎么开始干zd.我以我现在手头上正在做的事情告诉大家,如何做一个CA.
有了(jin)BC Provider,开CA,真的是q么?