天威(iTrus)jar包的重构

最近在看海尔快捷通的文档,他使用的是一个天威加密的工具。给的官方demo里,需要引入iTrus的jar包。此款jar包,官方的maven仓库中是没有的,当然可以放到公司的私服中使用。关于他的签名和加密规则,是我们需要关心的。其实,完全可以不使用他们的jar包来实现此类功能。iTrus主要的功能,利用里一下两个jar包。

<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15 -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15</artifactId>
    <version>1.46</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcmail-jdk15 -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15</artifactId>
    <version>1.46</version>
</dependency>

其原理是:使用pfx内容,读取PrivateKey对象、X509Certificate对象,用其签名;使用cer文件读取X509Certificate对象,来实现加密。关于,验签等操作,需要自行阅读他们的代码了。关于以下的实例代码,pfxContent、cerContent是pfx和cer文件的全部内容的base64串。

以下是实例代码:

package core;

import config.DefaultConfig;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.jce.PKCS7SignedData;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Vector;

/**
 * 主要的加密类
 * @author carlos
 */
public class CoreEncryption {

    protected X509Certificate certificate;
    protected PrivateKey privateKey;
    protected Vector vector = new Vector();
    protected String signAlgorithm = "MD5withRSA";

    private static String PROVIDER = "BC";

    static {
        if (Security.getProvider(PROVIDER) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }

    }

    public void init(String pfxContent, String cerContent, String keyPassword) throws Exception {
        InputStream pfxStream = new ByteArrayInputStream(Base64.decode(pfxContent));
        KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(pfxStream, keyPassword.toCharArray());
        pfxStream.close();
        Enumeration enums = keyStore.aliases();

        while(enums.hasMoreElements()) {
            String keyAlias = (String)enums.nextElement();
            if (keyStore.isKeyEntry(keyAlias)) {
                this.privateKey = (PrivateKey)keyStore.getKey(keyAlias, keyPassword.toCharArray());
                this.certificate = (X509Certificate)keyStore.getCertificate(keyAlias);
            }
        }

        InputStream cerInputStream = new ByteArrayInputStream(Base64.decode(cerContent));

        CertificateFactory crf = CertificateFactory.getInstance("X.509");
        X509Certificate vectorCertificate = (X509Certificate)crf.generateCertificate(cerInputStream);
        this.vector.add(vectorCertificate);
    }

    public String encryptMessage(byte[] originalMessage) throws Exception {
        CMSEnvelopedDataGenerator envelopedGen = new CMSEnvelopedDataGenerator();
        if (this.vector.size() == 0) {
            throw new Exception("exception");
        } else {
            for(int i = 0; i < this.vector.size(); ++i) {
                envelopedGen.addKeyTransRecipient((X509Certificate)this.vector.elementAt(i));
            }

            CMSProcessableByteArray cMSProcessable = new CMSProcessableByteArray(originalMessage);

            try {
                CMSEnvelopedData enveloped = envelopedGen.generate(cMSProcessable, PKCSObjectIdentifiers.des_EDE3_CBC.getId(), PROVIDER);
                return new String(Base64.encode(enveloped.getEncoded()), DefaultConfig.CHARSET);
            } catch (Exception e) {
                throw new Exception(e);
            }
        }
    }

    public String signMessage(byte[] originalMessage) throws Exception {
        if (this.privateKey != null && this.certificate != null) {
            X509Certificate[] chain = new X509Certificate[]{this.certificate};

            try {
                PKCS7SignedData p7Object = new PKCS7SignedData(this.privateKey, chain, this.signAlgorithm.substring(0, this.signAlgorithm.indexOf("with")));
                p7Object.update(originalMessage, 0, originalMessage.length);
                return new String(Base64.encode(p7Object.getEncoded()), DefaultConfig.CHARSET);
            } catch (Exception e) {
                throw new Exception(e);
            }
        } else {
            throw new Exception("参数为null!");
        }
    }

}

  • 这样的写法,可以把pfx和cer文件,以字符串的形式保存,实现所有密钥相关参数的统一管理。
  • 坏处是:文本的内容太大,可能每次调用传输效率需要考虑,但业务系统可以利用缓存,提高效率。

发表评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.