A. 使用openssl 创建pkcs12 keystore 为什么会出错
(1)Openssl生成公私钥
使用Openssl是为了生成公钥和私钥对,用于外部商户系统和xxx系统之间报文的安全性验证。如果使用者不需要生成公私钥,而是直接对报文进行处理,则参考第四部分,计算摘要及签名值。
1. 安装openssl步骤直接点击exe文件。出现需要安装vs2008插件的,直接忽略。
2. 在安装过程中找到OpenSSL相应的安装目录,进入bin目录下找到openssl.exe可执行文件,点击运行。然后分别按顺序输入如下命令:
a. genrsa –out private-rsa.key 1024
说明:该命令是生成一个没有加密的私钥
genrsa 生成私钥文件,私钥存储在private-rsa.key中,长度为1024。out后面指定输出文件名。
private-rsa.key 为生成的私钥文件,但该文件必须经过处理得到私钥。
b. req –new –x509 –key private-rsa.key –days 750 –outpublic-rsa.cer
说明:根据private-rsa.key生成证书public-rsa.cer
-new 表示新的请求
-509 表示输出的证书结构
750表示证书有效天数
-out public-rsa.cer -out后面表示公钥证书,用于验证数字签名,此公钥证书或者公钥需要提前发送给需要验证本单位或部门数据的接收方。
c. pkcs12 –export –name test-alias –in public-rsa.cer–inkey private-rsa.key –out 99bill-rsa.pfx
说明:生成PKCS12 格式Keystore
密码前后输入要一致,这个密码在用Keystore生成公私钥过程中会用到。
Public-rsa.cer, private-rsa.key是之前生成的。
附1:
下述代码是从99bill-rsa.pfx中获取私钥的java版本代码。因为private-rsa.key中生成的私钥无法直接使用,必须进行一定的处理。
代码有几个注意点:
文件流初始化路径需要根据自己的实际路径来填写。
密码是在第二节中c步骤中的密码,本实例输入的是suning。
KeyStorekeyStore = KeyStore.getInstance("PKCS12");
= newFileInputStream("D:/OpenSSL/bin/99bill-rsa.pfx");
char[]nPassword = "suning".toCharArray();
StringkeyAlias = null;
keyStore.load(fileInputStream,nPassword);
fileInputStream.close();
System.out.println("keystoretype=" + keyStore.getType());
Enumeration<String>enumeration = keyStore.aliases();
if(enumeration.hasMoreElements())
{
keyAlias = (String) enumeration.nextElement();
System.out.println("alias=[" + keyAlias +"]");
}
System.out.println("iskey entry=" + keyStore.isKeyEntry(keyAlias));
PrivateKeyprikey = (PrivateKey) keyStore.getKey(keyAlias, nPassword);
//私钥转成字符串
StringprivateStr = Base64.encodeBase64String(prikey.getEncoded()).trim();
//生成公钥字符串,还可以通过cer证书生成
Certificatecert = keyStore.getCertificate(keyAlias);
PublicKeypubkey = cert.getPublicKey();
StringpublicStr = Base64.encodeBase64String(pubKey.getEncoded()).trim();
注意:
1. 所用类的说明:
Base64:
import org.apache.commons.net.util.Base64;
Certificate:
import java.security.cert.Certificate;
2. 在openssl生成公私钥过程中,用户输入了密码。本例中密码为suning。
1. 摘要及生成方法
摘要的生成过程(digest方法全部实现了下述3个过程):
1. 根据key对传来的map数据排序;
2. 生成a1=b1&a2=b2&a3=b3形式的字符串,排除某些字符串Key值;
3. 调用digest方法进行md5编码;
以上三步均通过Digest.digest()方法实现:
String digest = Digest.digest(Map<String,String> map, String... keys);
传递的http报文体body内容如a1=b1&a2=b2&a3=b3形式的字符串,提取出需要加签的字符串并转成map形式。execludeKes是要排除的字段,是一个字符串数组。
计算摘要这一步很关键,因为选取的字段要求发送方和接收方必须一致,即发送方对哪些字段计算摘要,那么同样地接收方也必须对相同的字段计算摘要,否则会报6601的错误。
说明:a. Map是存储了计算摘要的字段
b. keys表示排除的字段,不能用于计算摘要的字段,如signature,signAlgorithm
2. 公钥证书及字符串转换方法
转换的目的:便于存储。(商户直接提供公钥证书也可以,但是对于向验签系统提供公钥字符串的商户,需要用下述代码把公钥转成字符串)
1. 公钥/私钥字符串转成公钥/私钥,主要是把字符串转成公钥PublicKey
X509EncodedKeySpec pubKeySpec = newX509EncodedKeySpec(Base64.decodeBase64(strPubKey));
KeyFactorykeyFactory = KeyFactory.getInstance(RSA);
PublicKeypubKey = keyFactory.generatePublic(pubKeySpec);
2. 公钥或私钥转成Base64字符串:
StringpublicStr = Base64.encodeBase64String(pubKey.getEncoded()).trim();
3. 公私钥验证方法
验证目的:公私钥生成之后,需要验证是否匹配。(之前许多商户生成公私钥混乱,无法确定公私钥是否匹配就添加到验签系统中)。此代码由用户自己用junit验证运行。验证公私钥生成是否正确,如果result为true,则说明公私钥生成正确;否则生成的公私钥有问题,不能使用。
String prik1 ="";
String pubb ="";
String data ="wkk";
String digest =Digest.digest(data);
PrivateKey privateKey =RSAUtil.getPrivateKey(prik1);
String sign =RSAUtil.sign(digest, privateKey);
boolean result =RSAUtil.vertiy(digest, sign,
RSAUtil.getPublicKey(pubb));
System.out.println(result);
B. 在unbuntu下使用openssl 写一个加密的C程序,编译提示找不到头文件openssl/*.h
哥门 <openssl/aes.h> 里 的openssl只是文件夹名字而已,
在linux下面 /usr/local/include/ /usr/include/ 这两个路径是默认引用的。
所以你没加 -I 也是可以编译的 。
当交叉编译时,那就完全不一样了,必须配置好所有路径。
C. 求用OpenSSL做的RSA文件加密程序实例,VC++6.0的,各位大侠帮帮忙,急用呀,多谢啦
#include <openssl/rsa.h>
#include <openssl/sha.h>
int main()
{
RSA *r;
int bits=1024,ret,len,flen,padding,i;
unsigned long e=RSA_3;
BIGNUM *bne;
unsigned char*key,*p;
BIO *b;
unsigned charfrom[500],to[500],out[500];
bne=BN_new();
ret=BN_set_word(bne,e);
r=RSA_new();
ret=RSA_generate_key_ex(r,bits,bne,NULL);
if(ret!=1)
{
printf("RSA_generate_key_ex err!\n");
return -1;
}
/* 私钥i2d */
b=BIO_new(BIO_s_mem());
ret=i2d_RSAPrivateKey_bio(b,r);
key=malloc(1024);
len=BIO_read(b,key,1024);
BIO_free(b);
b=BIO_new_file("rsa.key","w");
ret=i2d_RSAPrivateKey_bio(b,r);
BIO_free(b);
/* 私钥d2i */
/* 公钥i2d */
/* 公钥d2i */
/* 私钥加密 */
flen=RSA_size(r);
printf("please select private enc padding : \n");
printf("1.RSA_PKCS1_PADDING\n");
printf("3.RSA_NO_PADDING\n");
printf("5.RSA_X931_PADDING\n");
scanf("%d",&padding);
if(padding==RSA_PKCS1_PADDING)
flen-=11;
else if(padding==RSA_X931_PADDING)
flen-=2;
else if(padding==RSA_NO_PADDING)
flen=flen;
else
{
printf("rsa not surport !\n");
return -1;
}
for(i=0;i<flen;i++)
memset(&from[i],i,1);
len=RSA_private_encrypt(flen,from,to,r,padding);
if(len<=0)
{
printf("RSA_private_encrypt err!\n");
return -1;
}
len=RSA_public_decrypt(len,to,out,r,padding);
if(len<=0)
{
printf("RSA_public_decrypt err!\n");
return -1;
}
if(memcmp(from,out,flen))
{
printf("err!\n");
return -1;
}
/* */
printf("please select public enc padding : \n");
printf("1.RSA_PKCS1_PADDING\n");
printf("2.RSA_SSLV23_PADDING\n");
printf("3.RSA_NO_PADDING\n");
printf("4.RSA_PKCS1_OAEP_PADDING\n");
scanf("%d",&padding);
flen=RSA_size(r);
if(padding==RSA_PKCS1_PADDING)
flen-=11;
else if(padding==RSA_SSLV23_PADDING)
flen-=11;
else if(padding==RSA_X931_PADDING)
flen-=2;
else if(padding==RSA_NO_PADDING)
flen=flen;
else if(padding==RSA_PKCS1_OAEP_PADDING)
flen=flen-2 * SHA_DIGEST_LENGTH-2 ;
else
{
printf("rsa not surport !\n");
return -1;
}
for(i=0;i<flen;i++)
memset(&from[i],i+1,1);
len=RSA_public_encrypt(flen,from,to,r,padding);
if(len<=0)
{
printf("RSA_public_encrypt err!\n");
return -1;
}
len=RSA_private_decrypt(len,to,out,r,padding);
if(len<=0)
{
printf("RSA_private_decrypt err!\n");
return -1;
}
if(memcmp(from,out,flen))
{
printf("err!\n");
return -1;
}
printf("test ok!\n");
RSA_free(r);
return 0;
}
上述程序中当采用公钥RSA_SSLV23_PADDING加密,用私钥RSA_SSLV23_PADDING解密时会报错,原因是openssl源代码错误:
rsa_ssl.c函数RSA_padding_check_SSLv23有:
if (k == -1) /* err */
{
RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23,RSA_R_SSLV3_ROLLBACK_ATTACK);
return (-1);
}
修改为k!=-1即可。
各种padding对输入数据长度的要求:
私钥加密:
RSA_PKCS1_PADDING RSA_size-11
RSA_NO_PADDING RSA_size-0
RSA_X931_PADDING RSA_size-2
公钥加密
RSA_PKCS1_PADDING RSA_size-11
RSA_SSLV23_PADDING RSA_size-11
RSA_X931_PADDING RSA_size-2
RSA_NO_PADDING RSA_size-0
RSA_PKCS1_OAEP_PADDING RSA_size-2 * SHA_DIGEST_LENGTH-2
D. 如何给JSP服务器Resin加上SSL认证
为最佳JSP服务器Resin加上SSL认证
Resin主要是作为WEB服务器的jsp/servlets运行平台。它支持许多WEB服务器软件,而且是完全免费的,并提供了对SUN的J2EE的支持,这要比其它相关的java和javascript开发和运行平台要好的多,而且速度非常快,并提供服务器端直接开发、编译和运行。因此,Resin受到了许多应用JSP的WEB站点的支持。
一、 在WEB服务器中使用OpenSSL套件
1、安装OpenSSL
想要Resin可以响应SSL请求,我们就必需保证WEB服务器上已经安装好了相关的SSL套件。对于中小企业来说,开源免费的OpenSSL提供与SSL相同的认证功能。
OpenSSL的Linux版本可以在www.openssl.org网站上下载。现在它的最新版本是OpenSSL 0.9.8j。
Resin通过它的libexec/libresinssl.so JNI库文件提供对OpenSSL的支持。如果是在类Linux系统下使用OpenSSL,在安装时可以通过下列命令将它安装到指定的位置:
./configure --with-openssl=/usr/local/ssl
如果我们是在Windows系统中使用Resin,那么,我们同样需要在此操作系统下先安装好OpenSSL。Windows下的OpenSSL在www.slproweb.com/procts/Win32OpenSSL.html下载,它的最新安装文件是Win32OpenSSL-0_9_8j.exe,其大小为7MB左右。
在Windows系统下,Resin的resinssl.dll文件中包含提供对OpenSSL支持的代码。(在Resin3.0以前的版本是通过resin.dll文件提供支持的。)因此,在Windows系统下只需要安装好OpenSSL就可以让Resin使用它了。OpenSSL在Windows系统下很容易安装,就如同安装其它的应用程序一样简单。
不过,在Windows系统下安装完OpenSSL后,还应当将一些需要的DLL文件复制到Resin的根目录当中。现在假设Resin安装在c:\resin-3.2.1目录,OpenSSL安装在c:\Program Files\GnuWin32目录。现在打开系统开始菜单的“运行”对话框,在运行框中输入CMD命令,回车后进入命令行终端界面。然后在命令行终端下就可以通过下列所示的命令将OpenSSL安装目录下的相关文件复制到Resin的根目录下:
cd resin-3.2.1
c:\Program Files\GnuWin32\bin\libssl32.dll c:\resin-3.2.1\libssl32.dll
c:\Program Files\GnuWin32\bin\libeay32.dll c:\resin-3.2.1\libeay32.dll
2、生成SSL认证私钥
SSL认证的密钥由OpenSSL来生成,生成后的密钥应当保存到相应的Resin目录中。因此,在生成密钥前,我们可以在Resin根目录中创建一个keys子目录用来保存将要创建的密钥。在类Linux系统下,我们可以通过下列方式来创建keys目录:
cd /resin
mkdir keys
在Windows系统下,我们可以在资源管理器中直接在Resin根目录下创建一个新文件夹,并命名为keys即可。
在生成密钥时,OpenSSL会根据其配置文件中设置的内容来生成。在类Linux系统下,这个缺省的配置文件可能在usr/ssl/openssl.cnf或/usr/share/ssl/openssl.cnf下。而Windows系统中不存在这样的文件。
当然,我们还可以自己创建一个相应的配置文件保存到Resin/keys/目录下。这样,在创建密钥时,OpenSSL也会根据这个配置文件中的内容来创建,而且,在创建密钥时不会要求我们根据提示输入缺省的相关信息了。
下面是一个openssl.cnf配置文件的相关内容实例:
[ req ]
default_bits = 1024 #在这里填入加密键的缺省位数
distinguished_name = req的名称
[ req_distinguished_name ]
C = 在这里填入国家的代码,例如CN,代表中国
C_default =
ST = 这里填写州或省名称
ST_default =
L = 城市
L_default =
O = 企业或机构名称
O_default =
OU = 组织中某个部门的名称,例如市场部
OU_default =
CN = 我们的网站域名,必需是全名,例如www.myweb.com
CN_default =
emailAddress = 联系的E-Mail邮箱地址
emailAddress_default =
完成OpenSSL配置文件的相关设置后,我们就可以开始为SSL认证创建一个私钥。在WEB服务器上创建私钥时,会要求我们输入相应的密码,这个密码将会在我们使用创建的私钥时要求被输入。因此要牢记这个密码并妥善地保管它。我们还必需将这个密码加入到Resin的配置文件当中。
在类Linux系统下创建私钥时,私钥的文件名可以由我们自己决定,可以通过下列所示命令来完成:
openssl genrsa -des3 -out myprikey.key 1024
在Windows系统下创建私钥。得先进入命令行终端界面,然后用CD命令切换到OpenSSL安装目录,再用下列命令产生私钥;
c:\Program Files\GnuWin32\bin\openssl.exe genrsa -des3 -out myprikey.key 1024
二、 创建或申请SSL证书:
为了能够加密与用户的会话数据,我们还必需为SSL认证创建或申请一个公钥证书。这个公钥证书在使用时会由Resin发送给用户的浏览器,以便浏览器能够加密其发送的数据。公钥证书可以由OPENSSL产生一个自签名证书,也可以到第三方SSL证书颁发机构申请一个公钥证书。要注意的是,自签名证书将不能被其浏览器所承认。
1、创建一个自签名证书
当我们只是用来测试WEB服务器的SSL安全连接,或者只是作为企业远程办公之用时,那么创建一个自签名证书将会为我们节省一笔小钱。但是,对于这样的自签证书,WEB浏览器是不会承认的,还会为此弹出一个警告框来提醒用户这个证书不是一个公认的SSL证书。不过,用户浏览器与WEB服务器之间的会话数据仍然是被SSL加密了的。
在类Linux系统下创建自签名证书,可以使用下列命令来完成:
openssl req -config ./openssl.cnf -new -key myprikey.key -x509 -out myself.crt
在Windows系统下创建自签名证书,在字符终端用CD命令进入OpenSSL安装目录后,可以通过下列命令完成:
c:\Program Files\GnuWin32\bin\openssl.exe req -config ./openssl.cnf -new -key myprikey.key -x509 -out myself.crt
其中,自签名证书的名称可以由我们自己决定,例在本例中为myself.crt,而“-key”参数后带的键文件是在上面我们创建的私钥文件,而命令中的“./openssl.cnf”表示当前目录下的OpenSSL的配置文件。
如果我们没有按前文所述方式生成一个OpenSSL配置文件,或者没有修改此配置文件中的缺少配置值,那么在创建过程中会要求我们提供一些基本的与WEB服务器相关的身份资料,例如企业名称和网站域名等信息。
2、创建一个证书请求文件
如果要使用第三方证书颁发机构上的证书,那么就必需先创建一个证书请求文件(CSR)。这个证书请求文件中包含有证书的公钥、企业名称、加密位数、地址和网站域名等信息。
当我们在第三方证书颁发机构上申请证书时,就会要求我们提交这个证书请求文件,然后,证书颁发机构才能将SSL证书颁发给我们。现在提供SSL证书的机构有许多,例如VeriSign公司就是其中最着名的代表。在生成证书请求文件时一定要注意,我们使用什么样的WEB服务器软件,就必需生成与它相兼容的证书请求文件,这样,SSL证书颁发机构颁发给我们的证书才能在此WEB服务器下使用。
在Linux系统下生成证书请求文件,可以使用下列命令达到目的:
openssl req -new -config ./openssl.cnf -key myprikey.key -out myprikey.csr
在Windows系统下生成证书请求文件,在命令行界面中通过CD命令进入OpenSSL安装目录后,通过下列命令来完成证书请求文件的生成:
c:\Program Files\GnuWin32\bin\openssl.exe req -new -config ./openssl.cnf -key myprikey.key –out myprikey.csr
证书请求文件的文件名可以由我们自己来决定,在本文中为myprikey.csr。在生成证书请求文件过程中会要求我们输入一些与WEB服务器身份相关的信息,例如网站域名和企业名称等。我们必需按要求如实填写。
当我们成功注册,并支付相应的年使用费之后,这些证书颁发机构就会将SSL证书发送到我们填写的电子邮箱当中。
三、 配置Resin使用私钥和SSL证书
要想Resin能够使用SSL认证,我们还必需对其配置文件resin.conf做相应的设置。具体要配置的内容包括:
...
keys/ myself.crt
keys/ myprikey.key
mypassword
其中,中的内容表示SSL连接使用的默认端口号,如果没有特别要求,可以保持默认。和之间的内容填入Resin可以使用的SSL认证公钥,在这里为myself.crt。和之间的内容填入Resin可以使用的私钥,在本文中为myprikey.key。至于和之间就是填入我们在创建私钥时设置的密码。
四、 测试Resin的SSL加密连接
当我们配置好Resin的SSL认证后,我们还可以通过一些方式来检验我们的配置是否正确。
在Windows系统下,我们就可以通过在WEB浏览器地址栏中输入https://URL(企业网站的域名)的方式,来验证WEB服务器是否对这样的URL地址做出正确响应。如果返回正常的内容,并且在WEB浏览器地址栏中显示出一个挂锁的标志,那么,Resin的SSL配置就算成功了。
在Linux系统下,除了可以上述方式来检验外,还可以通过下列方式来验证:
openssl s_client -connect www.myweb.com:443 –prexit
另外,我们还可以通过下列的JSP脚本来快速验证Resin是否对SSL做出反应:
Secure? <%= request.isSecure() %>
经过上述的检验操作后,如果都能得到WEB服务器的正确响应,那么就说明Resin已经能够提供对SSL技术的支持了。
也就是说,当用户通过WEB浏览器向WEB服务器发送一个SSL请求时,Resin就会为这个WEB浏览器提供SSL认证的公共密钥,然后,这个WEB浏览器就可以使用这个公共密钥来加密数据,而Resin将使用WEB服务器的SSL私钥对加密的数据进行解密。