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();
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;
}
}
}
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);
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;
}
}
}