创建 PKCS#10 CSR 和 HMAC 印章



我无法正确创建PKCS#10证书签名请求和HMAC印章。我需要创建它们并发送到远程服务,这将为我生成 PKCS#7 格式的证书。更确切地说:

Create a key pair for certificate and generate PKCS#10 request 
(private key is never sent to the remote service)   
 use: key length 1024bit, SHA-1 algorithm, DER –encoded  
 Subject info: CN=name, serialNumber=userID, C=country (as above)   
Create HMAC seal  
 use DER coded PKCS#10 above as input  
 SMS-activation code as the key (10-digits)   

我将结果包装到 SoapMessage 中并发送到远程服务并获得响应。响应为错误,因为 CSR 或 HMAC 生成不正确。远程服务不会发送更具体的错误消息,但正如我所说,错误是由于错误地生成的 CSR 或 HMAC。主题和 HMAC 键是远程服务给出的示例值,这就是为什么问题不能因为它们的原因。

这是我如何实现它的代码

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
public class CustomerCert {
    private final KeyPairGenerator keyGen;
    private final KeyPair keypair;
    private final PublicKey publicKey;
    private final PrivateKey privateKey;
    private final byte[] pkcs10;
    private HMac hmac;
    private byte[] hmacBytes;
    public CustomerCert(String company, String userId, String country) 
            throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
         keyGen = KeyPairGenerator.getInstance("DSA");
         keyGen.initialize(1024, new SecureRandom());
         keypair = keyGen.generateKeyPair();
         publicKey = keypair.getPublic();
         privateKey = keypair.getPrivate();
         pkcs10 = this.generatePKCS10(company, userId, country);
    }
    private byte[] generatePKCS10(String company, String userId, String country) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
        String sigAlg = "SHA1withDSA";  
        String params = "CN=" + company + ", serialNumber=" + userId + ", C=" + country;
        X500Principal principal = new X500Principal(params);  
        PKCS10CertificationRequest kpGen = new PKCS10CertificationRequest(sigAlg, principal, publicKey, new DERSet(), privateKey, null);
        byte[] c = kpGen.getEncoded();
        return c;
    }
    public String getCSRasString() throws UnsupportedEncodingException {
        return new String(pkcs10, "ASCII"); // ISO-8859-1
    }
    public byte[] createHMacSeal(byte[] message, String key) throws UnsupportedEncodingException
    {
        hmac = new HMac(new SHA1Digest());
        hmacBytes = new byte[hmac.getMacSize()];
        {
            hmac.init(new KeyParameter(Hex.decode(key)));
            hmac.update(message, 0, message.length);
            hmac.doFinal(hmacBytes, 0);
        }
        return hmacBytes;
    }
}

我不确定如何根据要求对 PKCS 请求进行 DER 编码?
另一个问题是如何给 hmac 密封一个 DER 编码的 pkcs 输入?最后,如何获取生成的HMAC密封的字节数组,因为远程服务需要它作为base64编码的字节数组?

编辑

正如@Jcs指出的那样,我的 PKCS 创建是正确的,但现在我不确定正确的 HMAC 创建。我现在从远程服务器得到了响应,我现在收到的错误消息是error in MAC value。我目前的 HMac 创建方法如下:

public byte[] createHMacSeal(byte[] message, String key)  {
        String messageString = new String(message, "US-ASCII");
        HMac hmac = new HMac(new SHA1Digest());
        byte[] resBuf = new byte[hmac.getMacSize()];
        {
            byte[] m = messageString.getBytes();
            if (messageString.startsWith("0x"))
            {
                m = Hex.decode(messageString.substring(2));
            }
            hmac.init(new KeyParameter(key.getBytes("US-ASCII")));
            hmac.update(m, 0, m.length);
            hmac.doFinal(resBuf, 0);
            hmacBytes = resBuf;
        }
        return hmacBytes;

public byte[] createHMacSeal(byte[] message, String key) {
        SecretKey secretKey = new SecretKeySpec(key.getBytes("US-ASCII"), "HMac-SHA1");
        Mac mac;
        mac = Mac.getInstance("HMac-SHA1", "BC");
        mac.init(secretKey);
        mac.reset();
        mac.update(message, 0, message.length);
        hmacBytes = mac.doFinal();
        return hmacBytes;
    }

这两种方法为 HMAC 返回不同的值。对于方法参数,byte[] message是 DER 编码的 PKCS getPKCS10(),第二个参数key是 10 个字符的字符串1234567890形式的 SMS 激活码。现在我真的很震惊,并尝试了许多不同的可能性,但来自远程服务器的错误消息仍然相同。

关于 PKCS#10 请求

首先,不要担心 PKCS#10 请求。它不包含私钥,只包含使用者名称和公钥。私钥仅用于对请求进行签名。此签名是私钥所有权证明,即证明您确实拥有与请求中的公钥相对应的私钥。您构建 PKCS#10 请求的方式似乎不错。

关于HMAC印章

我认为此印章用于使用共享密钥验证请求者的身份:短信激活码。我认为这是某种一次性密码。我不确定您是否必须对此代码进行十六进制解码,我认为您应该将此代码用作 10 字节 ascii 编码的字符串,即如果代码0123456789 HMAC 密钥0x30313233343536373839

关于算法

井。。。这仅取决于服务的期望和/或允许的内容。DSA 仅用于签名,RSA 同时用于签名和加密。

我想你会发现:

字符串

消息字符串 = 新字符串(消息,"US-ASCII");

和:

byte[] m = messageString.getBytes();

如果消息最初是 DER 编码的字节数组,则极不可能产生相同的值。如果你需要在某些时候处理字符串,我建议将所有内容转换为十六进制或 Base64,这样字节数组转换是明确的。

最新更新