在web开发中,采用RSA公钥密钥体系自制ukey,文件证书登录时,广泛的作法为:在浏览器端采用c++ activex控件,使用 c++的第三库openssl进行RAS加签操做,在服务器端采用java对客户端的签名进行验签操做。这就涉及到c++ openssl和java之间交互加签验签对客户端身份进行验证的过程。html
若是你经过搜索查到我这边文章,相信你必定发现,采用openssl加签后的 数据,在java端却验签不成功,使用openssl验签能够经过。问题在于openssl的公钥发在服务端转换成java RSA 公钥时有问题,openssl的公钥格式里附加了它本身的一些额外信息。因此在服务端java构造本身的pubkey时必须先剔除openssl的特有信息。java
例如若是我么采用openssl生成 modulus size 为1024, exponent为65537 的公钥秘钥对---RSA_generate_key(1024, 65537, NULL, NULL);那么咱们在java端经过openssl的公钥构造java格式的公钥时,咱们就必须采用以下方式得到modulus ,而后采用java的方式构造公钥,进行验签操做。c++
private static byte[] getModulus(byte[] pkData, int begin){web
byte[] modData = new byte[128] ;浏览器
byte[] ss = {pkData[0],pkData[1],pkData[2],pkData[3]};服务器
for(int i = 0, y = begin; i < 128; i++,y++){ide
modData[i] = pkData[y];测试
}编码
return modData;spa
}
/**
* 从openssl中提起相关的128为的公钥数据
* @param b64Str
* @return
*/
private static byte[] get128PkData(String b64Str){
String pk = b64Str.replace("-----BEGIN RSA PUBLIC KEY-----", "");//剔除前面的信息
pk = pk.replace("-----END RSA PUBLIC KEY-----", "");// 剔除后面的信息
byte[] pkData = Base64.decode(pk);
return getModulus(pkData, 7);//下标从7开始,得到128 bytes的modulus
}
/** 若是你问我里边到底加了一些什么信息,我也不知道,我是从下标1开始不断测试,才得出应该从下标7开始获取modulus值 ***/
/**
* 由1024位的公钥转换成x509格式的公钥
* @param modData
* @return
* @throws Exception
*/
private static PublicKey getPublicKey(byte[] modData) throws Exception{
KeyFactory keyf = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(modData), new BigInteger("65537"));
RSAPublicKey pk = (RSAPublicKey) keyf.generatePublic(pubKeySpec);
// 解密由base64编码的公钥,并构造X509EncodedKeySpec对象
java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
pk.getEncoded());
return keyf.generatePublic(bobPubKeySpec);
}
至于openssl我就再也不作介绍,网上有不少资料,并且它自己的文档也很齐全
在后面附上一些相关的类, SignProvider.java 端负责公钥转换和加签验签 Base64.java负责64为编码 fcOpenSslRef.rar---Openssl相关类
注:本人对c++也不熟,因此上面的一些c++代码只作参考。
原文:http://www.chlusoft.com/tech/347.jhtml