我坚持正确创建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
是SMS激活码,作为10个字符的字符串1234567890
。现在我真的很震惊,尝试了很多不同的可能性,但仍然从远程服务器发出相同的错误消息。
答案 0 :(得分:2)
首先,不要担心PKCS#10请求。它不包含私钥,只包含主题名称和公钥。私钥仅用于签署请求。此签名是私钥占有证明,即它证明您确实拥有与请求中的公钥对应的私钥。您构建PKCS#10请求的方式似乎很好。
我认为这个印章用于通过共享密钥验证请求者的身份:SMS激活码。我认为这是某种一次性密码。我不确定你必须对这段代码进行十六进制解码,我认为你应该使用这个代码作为10字节ascii编码的字符串,即如果代码是0123456789
,则HMAC密钥是0x30313233343536373839
。
嗯......它只取决于服务期望和/或允许的内容。 DSA仅用于签名,RSA适用于签名和加密。
答案 1 :(得分:0)
我想你会发现:
String messageString = new String(message,“US-ASCII”);
和
byte [] m = messageString.getBytes();
如果消息最初是DER编码的字节数组,则极不可能产生相同的值。如果你需要在某些时候处理字符串,我建议将所有内容转换为Hex或Base64,因此字节数组转换是明确的。