Posted on 2011-05-13 11:50
xsong 阅读(1687)
评论(0) 编辑 收藏 所属分类:
java
java 证书公钥加密
生成xml 使用http
post发送到servl
et ,
servlet私钥解密
xml格式
1
:消息格式:
XML
消息格式如下:
<?xml version="1.0"
encoding="UTF-8">
<Request>
<Head>
<Signed>Base64(sign((md5(LoginName + | +
LoginTimeSpan + | + PassWord)))</Signed>
</Head>
<body>
<LoginName
type="string"> Base64(DES(LoginName)</
LoginName>
<LoginTimeSpan
type="string">
Base64(DES(LoginTimeSpan))</LoginTimeSpan>
<Password
type="string">
Base64(DES(PassWord))(</Password>
</body>
</request>
2
:消息内容采用
DES
算法进行加密处理,
DES
的入口参数有三个:
Key
、
Data
、
IV
。其中
Key
为
8
个字节共
64
位,是
DES
算法的工作密钥;
Data
也为
8
个字节
64
位,是需要进行加密的数据
,IV
是双方协商好的初始化向量,要求双方一致,最后结果再进行
BASE64
编码处理,及
BASE64(DES(
传输的消息内容
))
。
3
:发送方在消息体
<Head>
节点中对消息进行签名,防止消息内容在传输途中被篡改
,
由大众版那边提供公钥证书,这边对
Base64(md5(LoginName +
| + LoginTimeSpan + | + PassWord))
进行签名(rsa-sha1)
package com.cmcc.common.util;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.springframework.core.io.ClassPathResource;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Date;
/**
* User: fengxuesong
* Date: 11-3-29
* Time: 下午12:03
*/
public class Sign {
//Des初始化向量
public static final byte[] IV = new byte[]{-29, 105, 5, 40, -94, -98, -113, -100};
public static final String prikey = "00000000";
public static void main(String args[]) throws Exception {
String keystorePath = "F:\\idea-projects\\OSP\\src\\main\\webapp\\WEB-INF\\classes\\feinno.keystore";
String certPath = "F:\\idea-projects\\OSP\\src\\main\\webapp\\WEB-INF\\classes\\feinno.cer";
File keystoreFile=new ClassPathResource("feinno.keystore").getFile();
File certPathFile=new ClassPathResource("feinno.cer").getFile();
if(keystoreFile!=null){
keystorePath=keystoreFile.getPath();
}
if(certPathFile!=null){
certPath=certPathFile.getPath();
}
//初始化data
String loginName = "1";
String loginTimeSpan = new Date().toString();
String password = "111111";
StringBuffer data = new StringBuffer();
data.append(loginName).append("|").append(loginTimeSpan).append("|").append(password);
//生成 data MD5加密
byte[] headTextWithMD5 = encryptWithMD5(data);
//------------------私钥加密-----------------
String storepass = "feinno";//生成证书库时输入的密码
String storeKeyName = "feinno"; //证书别名
String headSigned = new BASE64Encoder().encode(sing(headTextWithMD5, storepass, storeKeyName,keystorePath));
String content = xml2String(encodeDesWithBase64(prikey, loginName), encodeDesWithBase64(prikey, loginTimeSpan), encodeDesWithBase64(prikey, password), headSigned);
//---------------------发送http请求
String url = "http://localhost:8080/auth";
String backinfo = sendPost(content, url);
System.out.println("validate:" + backinfo);
//-----------------模拟 收到http请求 收到的xml 生成 bean
// Request request = xml2Bean(content);
// String acceptHeadSigned = request.getHead().getSigned();
// String acceptLoginName = decodeDesWithBase64(prikey, request.getBody().getLoginName());
// String acceptLoginTimeSpan = decodeDesWithBase64(prikey, request.getBody().getLoginTimeSpan());
// String acceptPassword = decodeDesWithBase64(prikey, request.getBody().getPassword());
// StringBuffer acceptData = new StringBuffer();
// acceptData.append(acceptLoginName).append("|").append(acceptLoginTimeSpan).append("|").append(acceptPassword);
// //-----------------公钥验证
// byte[] verifyText = encryptWithMD5(acceptData);// encryptWithMD5(acceptData);
//
// boolean verifyFlag = verify(verifyText, new BASE64Decoder().decodeBuffer(acceptHeadSigned),certPath);
// if (verifyFlag)
// System.out.println("verify success");
// else
// System.out.println("verify faile");
}
/**
* @param plainText 需要验证的内容
* @param headSigned 私钥生成的签名
* @return
*/
public static boolean verify(byte[] plainText, byte[] headSigned,String certPath) throws Exception {
InputStream streamCert = new FileInputStream(certPath);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
Certificate cert = factory.generateCertificate(streamCert);
Signature rsa = Signature.getInstance("SHA1WithDSA");
PublicKey publicKey = cert.getPublicKey();
rsa.initVerify(publicKey);
rsa.update(plainText);
if (rsa.verify(headSigned)) {
return true;
} else {
return false;
}
}
/**
* @param plainText 签名的内容
* @param storepass 访问证书的密码
* @param storeKeyName 证书别名
* @return
*/
public static byte[] sing(byte[] plainText, String storepass, String storeKeyName , String keystorePath) throws Exception {
FileInputStream in = new FileInputStream(keystorePath);
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(in, storepass.toCharArray());
//获取私钥
PrivateKey priKey = (PrivateKey) ks.getKey(storeKeyName, storepass.toCharArray());
//用私钥签名
Signature sig = Signature.getInstance("SHA1WithDSA");
sig.initSign(priKey);
sig.update(plainText);
return sig.sign();
}
/**
* 数据MD5加密
*
* @param data
* @return
* @throws NoSuchAlgorithmException
*/
public static byte[] encryptWithMD5(StringBuffer data) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(data.toString().getBytes());
return md5.digest();
}
/**
* 用 httpClient 发送 post请求
*
* @param content 发送内容
* @param url
* @return 返回 response
* @throws IOException
*/
public static String sendPost(String content, String url) throws IOException {
String backinfo = "";
HttpClient httpclient = new HttpClient();
httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(1000);
PostMethod post = new PostMethod(url);
post.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,500);
post.setParameter("sign", content);
try {
httpclient.executeMethod(post);
int code = post.getStatusCode();
if (code == HttpStatus.SC_OK) {
backinfo = new String(post.getResponseBodyAsString());
}
} finally {
post.releaseConnection();
}
return backinfo;
}
/**
* xml转bean
*
* @param xml
* @return
*/
public static Request xml2Bean(String xml) throws Exception {
JAXBContext context = JAXBContext.newInstance(Request.class);
Unmarshaller um = context.createUnmarshaller();
InputStream inStream = new ByteArrayInputStream(xml.getBytes());
Request request = (Request) um.unmarshal(inStream);
return request;
}
/**
* 生成xml对应的字符转
*
* @param loginName 登录名
* @param loginTimeSpan 时间戳
* @param password 密码
* @param headSigned 证书鉴权
* @return
* @throws Exception
*/
public static String xml2String(String loginName, String loginTimeSpan, String password, String headSigned) throws Exception {
JAXBContext context = JAXBContext.newInstance(Request.class);
Request request = new Request();
Head head = new Head();
head.setSigned(headSigned);
Body body = new Body();
body.setLoginName(loginName);
body.setLoginTimeSpan(loginTimeSpan);
body.setPassword(password);
request.setHead(head);
request.setBody(body);
Marshaller m = context.createMarshaller();
OutputStream outStream = new ByteArrayOutputStream();
m.marshal(request, outStream);
return outStream.toString();
}
/**
* 数据 Des加密, 并Base64编码, 解决 des 加密数据必须是8个字节的倍数
*
* @param priKey 密钥
* @param data 需要加密的数据
* @return 已加密数据
*/
public static String encodeDesWithBase64(String priKey, String data) throws Exception {
DESKeySpec desKS = new DESKeySpec(priKey.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey sk = skf.generateSecret(desKS);
Cipher cip = Cipher.getInstance("DES/CBC/PKCS5Padding");
cip.init(Cipher.ENCRYPT_MODE, sk, new IvParameterSpec(IV));
byte bb[] = cip.doFinal(data.getBytes());
return new BASE64Encoder().encode(bb);
}
/**
* 数据 Des解密,
*
* @param priKey 密钥
* @param data 以加密数据
* @return 解密数据
* @throws Exception
*/
public static String decodeDesWithBase64(String priKey, String data) throws Exception {
DESKeySpec desKS = new DESKeySpec(priKey.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey sk = skf.generateSecret(desKS);
Cipher cip = Cipher.getInstance("DES/CBC/PKCS5Padding");
cip.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec(IV));
byte bb[] = cip.doFinal(new BASE64Decoder().decodeBuffer(data));
return new String(bb);
}
/**
* 生成xml的bean
*/
@XmlRootElement
public static class Request {
public Request() {
}
Head head;
Body body;
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
}
public static class Head {
public Head() {
}
String signed;
public String getSigned() {
return signed;
}
public void setSigned(String signed) {
this.signed = signed;
}
}
public static class Body {
public Body() {
}
String loginName;
String loginTimeSpan;
String password;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLoginTimeSpan() {
return loginTimeSpan;
}
public void setLoginTimeSpan(String loginTimeSpan) {
this.loginTimeSpan = loginTimeSpan;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}