浏览 21992 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-01-24
服务器端模拟CA。初始化时,给我们信任的用户发放唯一身份标识的数字证书。用户每次登陆时,我们会验证其数字证书是不是此用户(C/S)。 我的思路是,先在信任的用户端发放一个唯一标识的数字证书。用户登陆时,我们来验证数字证书是不是此用户。。这样客户端必定要有一个地方存储数字证书。当用户和服务器交互时,我们怎么利用数字证书来完成加密和解密呢。在程序中怎么利用数字证书的public key 和private key对信息进行加密和解密。。。还有在服务器端利用一个根证书来签名的话,生成的数字证书都是 trustedCertEntry,而不是 keyEntry,当客户端存储此数字证书,必然造成客户发到服务器端的信息无法加密。 public void createCert(String username,String password) { String name = "c:/storeLib"; String pass = "123456"; String certPass = "111111"; //根证书 String alias = "mystore"; String newCert = username+password; System.out.println(newCert); try { //载入证书库 FileInputStream in = new FileInputStream(name); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(in,pass.toCharArray()); //得到签发者 Certificate c = ks.getCertificate(alias); byte[] encode1 = c.getEncoded(); X509CertImpl cimp1 = new X509CertImpl(encode1); X509CertInfo cinfo1 = (X509CertInfo) cimp1.get(X509CertImpl.NAME+"."+X509CertImpl.INFO); X500Name issuer = (X500Name) cinfo1.get(X509CertInfo.SUBJECT+"."+CertificateIssuerName.DN_NAME); PrivateKey pk = (PrivateKey)ks.getKey(alias, certPass.toCharArray()); Calendar calendar = Calendar.getInstance(); Date begindate = calendar.getTime(); calendar.add(Calendar.YEAR, 1); Date enddate = calendar.getTime(); //设置新证书的有效期 CertificateValidity cv = new CertificateValidity(begindate,enddate); cinfo1.set(X509CertInfo.VALIDITY, cv); //设置SN号 int sn = (int)(begindate.getTime()/1000); CertificateSerialNumber csn = new CertificateSerialNumber(sn); cinfo1.set(X509CertInfo.SERIAL_NUMBER,csn); //设置新证书的签发者 cinfo1.set(X509CertInfo.ISSUER+"."+CertificateIssuerName.DN_NAME, issuer); //设置新证书的算法 AlgorithmId algorithm = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); cinfo1.set(CertificateAlgorithmId.NAME+"."+CertificateAlgorithmId.ALGORITHM, algorithm); //创建新证书 X509CertImpl newcert = new X509CertImpl(cinfo1); newcert.sign(pk,"MD5WithRSA"); System.out.println(newcert); ks.setCertificateEntry(newCert, newcert); FileOutputStream out = new FileOutputStream(name); ks.store(out, pass.toCharArray()); } catch (Exception e) { e.printStackTrace(); } } 上面的代码是利用根证书的private key 完成证书的签发。所以签发的证书都是trustedCertEntry。而不是keyEntry。 google了很多文档。都是和此代码类似。大多是利用ssl来完成加密通信的。而不是利用数字证书的公钥和私钥来完成加密和解密的。。。。 希望能得到大家的帮助。谢谢、 现在实现身份验证,通过数字签名来验证了。利用数字证书的私钥来完成签名,引用发出的公钥来验证签名。也是可以完成身份验证的。。。 Signature s = Signature.getInstance("MD5WithRSA"); //或得数字证书的私钥 PrivateKey prk = (PrivateKey)ks.getKey(alias, pass.toCharArray()); //用私钥初始化Signature s.initSign(prk); //传入要签名的数据 s.update(data) //执行签名 byte[] signaturedata = s.sign(); //利用公钥验证 PublicKey pbk = c.getPublicKey(); Signature s = Signature.getInstance("MD5WithRSA"); s.initVerify(pbk); //传入要签名的数据 s.update(mes); try { s.verify(signeddata); return "身份验证成功:" + cinfo1.toString(); } catch (SignatureException e) { return "身份验证失败"; } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-01-24
我看你的思路似乎不太清楚。
我以前的经验是,在web上利用数字证书加密和用户认证有两条路: 1.利用SSL 3.0。 SSL 3.0可以支持服务端和客户端双向认证。在连接初始时进行验证,以后使用SSL对称加密所有数据。 这种方法对程序是基本透明的,在J2EE里,用request可以获得用户证书对象。 但这这里的问题是,所有传输的数据是对称加密的,没有用户私钥的数字签名,因此标准意义上的不可抵赖性是没有的。 2.利用Applet或Com自行实现认证和加密。 利用上述技术,将所有传递的数据,以数字信封的形式加密并加以数字签名,双方通信则除了实现认证、加密外,可实现标准的不可抵赖性。 |
|
返回顶楼 | |
发表时间:2007-01-24
客户端是浏览器还是自己实现 的客户端?
浏览器的话,不知道你登录过网上银行么,例如建行的网上银行.在与服务器交互的时候,服务器是可以要求客户端用证书登录的 ,这样就会弹出一个证书选择对话框,选择了证书后,浏览器发送的信息就是通过证书公钥加密过的数据了. 自己实现的客户端的话,你也要在客户端弹出一个选择证书对话框才可以.然后就可以调用系统api通过公钥加密数据. |
|
返回顶楼 | |
发表时间:2007-01-24
qingyujingyu427 写道 客户端是浏览器还是自己实现 的客户端?
一个用户获得数字证书,该数字证书能到的只有公钥信息和签发者的主体。用户可以通过公钥来对自己向服务器端所发的信息加密。服务器通过该数字证书的签发者的私钥来解密吗?
浏览器的话,不知道你登录过网上银行么,例如建行的网上银行.在与服务器交互的时候,服务器是可以要求客户端用证书登录的 ,这样就会弹出一个证书选择对话框,选择了证书后,浏览器发送的信息就是通过证书公钥加密过的数据了. 自己实现的客户端的话,你也要在客户端弹出一个选择证书对话框才可以.然后就可以调用系统api通过公钥加密数据. 因为用户存储的数字证书应该是trustedCertEntry,也就是不存在私钥的数字证书。不存在私钥的话,怎么完成服务器端发来的信息进行解密呢。 我想使用客户端来完成身份的验证,和通信的加密。 |
|
返回顶楼 | |
发表时间:2007-01-24
先说一下基本概念.
当客户端向服务器端传输数据的时候,是用服务器端的证书的公钥进行加密,服务器接受到数据后,通过自己的私钥进行解密. 服务器端向客户端传输数据时,服务器用客户端证书的公钥进行加密,客户端收到数据的时候通过自己的私钥进行解密. 按照你的想法,应该客户端的证书必须是一个包含公钥和私钥的证书,据我所知java api应该无法生成包含私钥信息的证书(这点我不确定).openssl提供的工具可以生成这种证书. 你首先应该想办法生成一个带有私钥的证书.然后再考虑别的. 介绍一下签名和加密: 客户端向服务器端发送数据时,首先生成一个随机密钥(用于3DES算法),然后通过3DES算法将要传输的数据加密,然后再通过服务器的公钥将这个密钥加密(假设这个数据为key),然后再用自己的私钥对key加密(也就是签名). 服务器端收到数据后........逆向进行,就既验证了签名,又保证了数据安全. 我只是大体举个例子,具体怎么实现可以自己决定.ssl协议规范了一些做法,你可以看看. 另外可以去www.ietf.org搜索一下跟证书或ssl等有关的协议. |
|
返回顶楼 | |
发表时间:2007-01-24
谢谢,qingyujingyu427的回复。
java api 我也不知道能不能作到生成私钥的证书。但是可以通过jdk 中提供的keytools工具是可以完成的。。 SSL,JAVA 提供了些API。Lucas Lee说可以通过request来获得,但是怎么获得指定的数字证书呢。 String certAttribute = "javax.servlet.request.X509Certificate"; X509Certificate certificate = (X509Certificate)request.getAttribute(certAttribute); IE里面有很多证书,上面的代码可以或得指定的证书吗? 我想我得去看看SSL的资料了。。。现在很迷惑。 可惜找不到什么易懂的代码参考。 |
|
返回顶楼 | |
发表时间:2007-01-24
cary 写道 谢谢,qingyujingyu427的回复。
java api 我也不知道能不能作到生成私钥的证书。但是可以通过jdk 中提供的keytools工具是可以完成的。。 SSL,JAVA 提供了些API。Lucas Lee说可以通过request来获得,但是怎么获得指定的数字证书呢。 String certAttribute = "javax.servlet.request.X509Certificate"; X509Certificate certificate = (X509Certificate)request.getAttribute(certAttribute); IE里面有很多证书,上面的代码可以或得指定的证书吗? 我想我得去看看SSL的资料了。。。现在很迷惑。 可惜找不到什么易懂的代码参考。 没错,就是用这个方法获得客户端通过验证的证书.当然是在SSL协议验证完毕后才可以获得. 至于生成证书什么的,典型的,不应该由程序自动处理,而是用单独的应用去做,比如windows 2000 advanced server里面有Microsoft certification center(好像是这个名字),用这个应用去处理管理用户的证书。 |
|
返回顶楼 | |
发表时间:2007-01-24
引用 SSL,JAVA 提供了些API。Lucas Lee说可以通过request来获得,但是怎么获得指定的数字证书呢。 String certAttribute = "javax.servlet.request.X509Certificate"; X509Certificate certificate = (X509Certificate)request.getAttribute(certAttribute); IE里面有很多证书,上面的代码可以或得指定的证书吗? IE里面的确是有很多证书,所以ie端会自动弹出个对话框让用户选择他要用的证书的,所以你在服务器端不用关心这些问题,你获得哪个就用哪个,如果验证不通过,你就认为他不合法就可以了. 我认为JAVA提供的SSL api已经够强大,够易用了.以前用delphi和.net 1.0做客户端时那才叫郁闷.delphi是文档太差,.net 1.0压根就不支持,而且没有开源. 而且如果客户端是IE的话,你关心的问题就更少了,我感觉大部分工作,IE和应用服务器都已经做了,你就着重看一下ssl理解一下,弄清楚哪些是你还需要做的,哪些ie和应用服务器都已经做了就可以了. 另外搜索一下 PKI(Public Key Infrastructure),理解一下相关概念.内容其实很少,主要是概念理解了可能你就会感觉恍然大悟. 我觉得你可能是现在因为是第一次接触这种东西,可能由于概念还不是很理解,所以感觉无从下手. |
|
返回顶楼 | |