java

位置:IT落伍者 >> java >> 浏览文章

Java加密技术(九)


发布日期:2022年06月29日
 
Java加密技术(九)

在Java加密技术(八)中我们模拟了一个基于RSA非对称加密网络的安全通信现在我们深度了解一下现有的安全网络通信——SSL

我们需要构建一个由CA机构签发的有效证书这里我们使用上文中生成的自签名证书zlexcer

这里我们将证书导入到我们的密钥库

Shell代码

keytool import alias  file d/zlexcer keystore d/zlexkeystore

其中

import表示导入

alias指定别名这里是

file指定算法这里是d/zlexcer

keystore指定存储位置这里是d/zlexkeystore

在这里我使用的密码为

控制台输出

Console代码

输入keystore密码

再次输入新密码:

所有者:CN= OU=zlex O=zlex L=BJ ST=BJ C=CN

签发人:CN= OU=zlex O=zlex L=BJ ST=BJ C=CN

序列号:aedf

有效期: Thu May :: CST 至Wed Aug :: CST

证书指纹:

MD::CA:E::E:DF:AD::::F:A:AD:FC::A

SHA:::::::F::CA::A:D:A:CF::D:C:D:C:C

签名算法名称:SHAwithRSA

版本:

信任这个认证? [否] y

认证已添加至keystore中

OK最复杂的准备工作已经完成

接下来我们将域名定位到本机上打开C\Windows\System\drivers\etc\hosts文件将绑定在本机上在文件末尾追加 现在通过地址栏访问或者通过ping命令如果能够定位到本机域名映射就搞定了

现在配置tomcat先将zlexkeystore拷贝到tomcat的conf目录下然后配置serverxml将如下内容加入配置文件

Xml代码

<Connector

SSLEnabled=true

URIEncoding=UTF

clientAuth=false

keystoreFile=conf/zlexkeystore

keystorePass=

maxThreads=

port=

protocol=HTTP/

scheme=https

secure=true

sslProtocol=TLS />

注意clientAuth=false测试阶段置为false正式使用时建议使用true现在启动tomcat访问

显然证书未能通过认证这个时候你可以选择安装证书(上文中的zlexcer文件就是证书)作为受信任的根证书颁发机构导入再次重启浏览器(IE其他浏览器对于域名不支持本地方式访问)访问你会看到地址栏中会有个小锁就说明安装成功所有的浏览器联网操作已经在RSA加密解密系统的保护之下了但似乎我们感受不到

这个时候很多人开始怀疑如果我们要手工做一个这样的https的访问是不是需要把浏览器的这些个功能都实现呢?不需要!

接着上篇内容给出如下代码实现

Java代码

import javaioFileInputStream;

import javasecurityKeyStore;

import javasecurityPrivateKey;

import javasecurityPublicKey;

import javasecuritySignature;

import javasecuritycertCertificate;

import javasecuritycertCertificateFactory;

import javasecuritycertXCertificate;

import javautilDate;

import javaxcryptoCipher;

import sslHttpsURLConnection;

import sslKeyManagerFactory;

import sslSSLContext;

import sslSSLSocketFactory;

import sslTrustManagerFactory;

/**

* 证书组件

*

* @author 梁栋

* @version

* @since

*/

public abstract class CertificateCoder extends Coder {

/**

* Java密钥库(Java Key StoreJKS)KEY_STORE

*/

public static final String KEY_STORE = JKS;

public static final String X = X;

public static final String SunX = SunX;

public static final String SSL = SSL;

/**

* 由KeyStore获得私钥

*

* @param keyStorePath

* @param alias

* @param password

* @return

* @throws Exception

*/

private static PrivateKey getPrivateKey(String keyStorePath String alias

String password) throws Exception {

KeyStore ks = getKeyStore(keyStorePath password);

PrivateKey key = (PrivateKey) ksgetKey(alias passwordtoCharArray());

return key;

}

/**

* 由Certificate获得公钥

*

* @param certificatePath

* @return

* @throws Exception

*/

private static PublicKey getPublicKey(String certificatePath)

throws Exception {

Certificate certificate = getCertificate(certificatePath);

PublicKey key = certificategetPublicKey();

return key;

}

/**

* 获得Certificate

*

* @param certificatePath

* @return

* @throws Exception

*/

private static Certificate getCertificate(String certificatePath)

throws Exception {

CertificateFactory certificateFactory = CertificateFactory

getInstance(X);

FileInputStream in = new FileInputStream(certificatePath);

Certificate certificate = certificateFactorygenerateCertificate(in);

inclose();

return certificate;

}

/**

* 获得Certificate

*

* @param keyStorePath

* @param alias

* @param password

* @return

* @throws Exception

*/

private static Certificate getCertificate(String keyStorePath

String alias String password) throws Exception {

KeyStore ks = getKeyStore(keyStorePath password);

Certificate certificate = ksgetCertificate(alias);

return certificate;

}

/**

* 获得KeyStore

*

* @param keyStorePath

* @param password

* @return

* @throws Exception

*/

private static KeyStore getKeyStore(String keyStorePath String password)

throws Exception {

FileInputStream is = new FileInputStream(keyStorePath);

KeyStore ks = KeyStoregetInstance(KEY_STORE);

ksload(is passwordtoCharArray());

isclose();

return ks;

}

/**

* 私钥加密

*

* @param data

* @param keyStorePath

* @param alias

* @param password

* @return

* @throws Exception

*/

public static byte[] encryptByPrivateKey(byte[] data String keyStorePath

String alias String password) throws Exception {

// 取得私钥

PrivateKey privateKey = getPrivateKey(keyStorePath alias password);

// 对数据加密

Cipher cipher = CiphergetInstance(privateKeygetAlgorithm());

cipherinit(CipherENCRYPT_MODE privateKey);

return cipherdoFinal(data);

}

/**

* 私钥解密

*

* @param data

* @param keyStorePath

* @param alias

* @param password

* @return

* @throws Exception

*/

public static byte[] decryptByPrivateKey(byte[] data String keyStorePath

String alias String password) throws Exception {

// 取得私钥

PrivateKey privateKey = getPrivateKey(keyStorePath alias password);

// 对数据加密

Cipher cipher = CiphergetInstance(privateKeygetAlgorithm());

cipherinit(CipherDECRYPT_MODE privateKey);

return cipherdoFinal(data);

}

/**

* 公钥加密

*

* @param data

* @param certificatePath

* @return

* @throws Exception

*/

public static byte[] encryptByPublicKey(byte[] data String certificatePath)

throws Exception {

// 取得公钥

PublicKey publicKey = getPublicKey(certificatePath);

// 对数据加密

Cipher cipher = CiphergetInstance(publicKeygetAlgorithm());

cipherinit(CipherENCRYPT_MODE publicKey);

return cipherdoFinal(data);

}

/**

* 公钥解密

*

* @param data

* @param certificatePath

* @return

* @throws Exception

*/

public static byte[] decryptByPublicKey(byte[] data String certificatePath)

throws Exception {

// 取得公钥

PublicKey publicKey = getPublicKey(certificatePath);

// 对数据加密

Cipher cipher = CiphergetInstance(publicKeygetAlgorithm());

cipherinit(CipherDECRYPT_MODE publicKey);

return cipherdoFinal(data);

}

/**

* 验证Certificate

*

* @param certificatePath

* @return

*/

public static boolean verifyCertificate(String certificatePath) {

return verifyCertificate(new Date() certificatePath);

}

/**

* 验证Certificate是否过期或无效

*

* @param date

* @param certificatePath

* @return

*/

public static boolean verifyCertificate(Date date String certificatePath) {

boolean status = true;

try {

// 取得证书

Certificate certificate = getCertificate(certificatePath);

// 验证证书是否过期或无效

status = verifyCertificate(date certificate);

} catch (Exception e) {

status = false;

}

return status;

}

/**

* 验证证书是否过期或无效

*

* @param date

* @param certificate

* @return

*/

private static boolean verifyCertificate(Date date Certificate certificate) {

boolean status = true;

try {

XCertificate xCertificate = (XCertificate) certificate;

xCertificatecheckValidity(date);

} catch (Exception e) {

status = false;

}

return status;

}

/**

* 签名

*

* @param keyStorePath

* @param alias

* @param password

*

* @return

* @throws Exception

*/

public static String sign(byte[] sign String keyStorePath String alias

String password) throws Exception {

// 获得证书

XCertificate xCertificate = (XCertificate) getCertificate(

keyStorePath alias password);

// 获取私钥

KeyStore ks = getKeyStore(keyStorePath password);

// 取得私钥

PrivateKey privateKey = (PrivateKey) ksgetKey(alias password

toCharArray());

// 构建签名

Signature signature = SignaturegetInstance(xCertificate

getSigAlgName());

signatureinitSign(privateKey);

signatureupdate(sign);

return encryptBASE(signaturesign());

}

/**

* 验证签名

*

* @param data

* @param sign

* @param certificatePath

* @return

* @throws Exception

*/

public static boolean verify(byte[] data String sign

String certificatePath) throws Exception {

// 获得证书

XCertificate xCertificate = (XCertificate) getCertificate(certificatePath);

// 获得公钥

PublicKey publicKey = xCertificategetPublicKey();

// 构建签名

Signature signature = SignaturegetInstance(xCertificate

getSigAlgName());

signatureinitVerify(publicKey);

signatureupdate(data);

return signatureverify(decryptBASE(sign));

}

/**

* 验证Certificate

*

* @param keyStorePath

* @param alias

* @param password

* @return

*/

public static boolean verifyCertificate(Date date String keyStorePath

String alias String password) {

boolean status = true;

try {

Certificate certificate = getCertificate(keyStorePath alias

password);

status = verifyCertificate(date certificate);

} catch (Exception e) {

status = false;

}

return status;

}

/**

* 验证Certificate

*

* @param keyStorePath

* @param alias

* @param password

* @return

*/

public static boolean verifyCertificate(String keyStorePath String alias

String password) {

return verifyCertificate(new Date() keyStorePath alias password);

}

/**

* 获得SSLSocektFactory

*

* @param password

* 密码

* @param keyStorePath

* 密钥库路径

*

* @param trustKeyStorePath

* 信任库路径

* @return

* @throws Exception

*/

private static SSLSocketFactory getSSLSocketFactory(String password

String keyStorePath String trustKeyStorePath) throws Exception {

// 初始化密钥库

KeyManagerFactory keyManagerFactory = KeyManagerFactory

getInstance(SunX);

KeyStore keyStore = getKeyStore(keyStorePath password);

keyManagerFactoryinit(keyStore passwordtoCharArray());

// 初始化信任库

TrustManagerFactory trustManagerFactory = TrustManagerFactory

getInstance(SunX);

KeyStore trustkeyStore = getKeyStore(trustKeyStorePath password);

trustManagerFactoryinit(trustkeyStore);

// 初始化SSL上下文

SSLContext ctx = SSLContextgetInstance(SSL);

ctxinit(keyManagerFactorygetKeyManagers() trustManagerFactory

getTrustManagers() null);

SSLSocketFactory sf = ctxgetSocketFactory();

return sf;

}

/**

* 为HttpsURLConnection配置SSLSocketFactory

*

* @param conn

* HttpsURLConnection

* @param password

* 密码

* @param keyStorePath

* 密钥库路径

*

* @param trustKeyStorePath

* 信任库路径

* @throws Exception

*/

public static void configSSLSocketFactory(HttpsURLConnection conn

String password String keyStorePath String trustKeyStorePath)

throws Exception {

connsetSSLSocketFactory(getSSLSocketFactory(password keyStorePath

trustKeyStorePath));

}

}

增加了configSSLSocketFactory方法供外界调用该方法为HttpsURLConnection配置了SSLSocketFactory当HttpsURLConnection配置了SSLSocketFactory后我们就可以通过HttpsURLConnection的getInputStreamgetOutputStream像往常使用HttpURLConnection做操作了尤其要说明一点未配置SSLSocketFactory前HttpsURLConnection的getContentLength()获得值永远都是

给出相应测试类

Java代码

import static orgjunitAssert*;

import javaioDataInputStream;

import javaioInputStream;

import URL;

import sslHttpsURLConnection;

import orgjunitTest;

/**

*

* @author 梁栋

* @version

* @since

*/

public class CertificateCoderTest {

private String password = ;

private String alias = ;

private String certificatePath = d:/zlexcer;

private String keyStorePath = d:/zlexkeystore;

private String clientKeyStorePath = d:/zlexclientkeystore;

private String clientPassword = ;

@Test

public void test() throws Exception {

Systemerrprintln(公钥加密——私钥解密);

String inputStr = Ceritifcate;

byte[] data = inputStrgetBytes();

byte[] encrypt = CertificateCoderencryptByPublicKey(data

certificatePath);

byte[] decrypt = CertificateCoderdecryptByPrivateKey(encrypt

keyStorePath alias password);

String outputStr = new String(decrypt);

Systemerrprintln(加密前: + inputStr + \n\r + 解密后: + outputStr);

// 验证数据一致

assertArrayEquals(data decrypt);

// 验证证书有效

assertTrue(CertificateCoderverifyCertificate(certificatePath));

}

@Test

public void testSign() throws Exception {

Systemerrprintln(私钥加密——公钥解密);

String inputStr = sign;

byte[] data = inputStrgetBytes();

byte[] encodedData = CertificateCoderencryptByPrivateKey(data

keyStorePath alias password);

byte[] decodedData = CertificateCoderdecryptByPublicKey(encodedData

certificatePath);

String outputStr = new String(decodedData);

Systemerrprintln(加密前: + inputStr + \n\r + 解密后: + outputStr);

assertEquals(inputStr outputStr);

Systemerrprintln(私钥签名——公钥验证签名);

// 产生签名

String sign = CertificateCodersign(encodedData keyStorePath alias

password);

Systemerrprintln(签名:\r + sign);

// 验证签名

boolean status = CertificateCoderverify(encodedData sign

certificatePath);

Systemerrprintln(状态:\r + status);

assertTrue(status);

}

@Test

public void testHttps() throws Exception {

URL url = new URL();

HttpsURLConnection conn = (HttpsURLConnection) urlopenConnection();

connsetDoInput(true);

connsetDoOutput(true);

nfigSSLSocketFactory(conn clientPassword

clientKeyStorePath clientKeyStorePath);

InputStream is = conngetInputStream();

int length = conngetContentLength();

DataInputStream dis = new DataInputStream(is);

byte[] data = new byte[length];

disreadFully(data);

disclose();

Systemerrprintln(new String(data));

conndisconnect();

}

}

注意testHttps方法几乎和我们往常做HTTP访问没有差别我们来看控制台输出

Console代码

<!

Licensed to the Apache Software Foundation (ASF) under one or more

contributor license agreements See the NOTICE file distributed with

this work for additional information regarding copyright ownership

The ASF licenses this file to You under the Apache License Version

(the License); you may not use this file except in compliance with

the License You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing software

distributed under the License is distributed on an AS IS BASIS

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied

See the License for the specific language governing permissions and

limitations under the License

>

<!DOCTYPE HTML PUBLIC //WC//DTD HTML Transitional//EN>

<HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>

<META httpequiv=ContentType content=text/html>

</HEAD>

<BODY>

<P>

<H>Apache Tomcat Examples</H>

<P></P>

<ul>

<li><a >Servlets examples</a></li>

<li><a >JSP Examples</a></li>

</ul>

</BODY></HTML>

通过浏览器直接访问你也会获得上述内容也就是说应用甲方作为服务器构建tomcat服务乙方可以通过上述方式访问甲方受保护的SSL应用并且不需要考虑具体的加密解密问题甲乙双方可以经过相应配置通过双方的tomcat配置有效的SSL服务简化上述代码实现完全通过证书配置完成SSL双向认证!

               

上一篇:java设计模式之Prototype(原型)

下一篇:Java与模式:合成模式