tldr:
当我已经用AES和已经用公钥加密的秘密密钥加密内容时,有没有办法创建CMS封装数据?
长版本:
我有一个应用程序,加密和解密数据与AES (CBC和GCM模式)。对称密钥使用RSA密钥对进行加密/解密。当用户请求数据时,我们在后端(Java)对其进行解密,并将其发送到浏览器
通常我们有公钥和私钥,但在某些情况下,要求我们没有私钥,解密应该在浏览器中进行(用户向PFX提供私钥)。这个问题的解决方案是PKI.js,它可以使用PFX和CMS封装数据来解密数据。
问题是,我们已经加密了数据,无法访问我们可以用来构建CMS封装数据的纯数据。
编辑:@dave_thompson_085感谢您的回复!我有一个后续问题。我没有在系统中持有证书,所以我唯一有的就是公钥。有没有办法让你的代码适应这个需求呢?
在你回答之前,我第二次加密数据,只是为了CMS封装的对象。在这段代码中,我只使用了公钥来生成接收器。有没有办法调整你的代码来生成只有公钥的reciepent?我之前的代码:
SubjectKeyIdentifier subjectKeyIdentifier = new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey);
JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
OAEPParameterSpec oaepSpec = new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(mgfDigest), PSource.PSpecified.DEFAULT);
AlgorithmIdentifier oaepAlgId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
RecipientInfoGenerator recipientInfoGenerator = new JceKeyTransRecipientInfoGenerator(subjectKeyIdentifier.getEncoded(),oaepAlgId,publicKey).setProvider("BC");
envelopedDataGenerator.addRecipientInfoGenerator(recipientInfoGenerator);那么散列算法呢?我是否需要一个或它只是一个额外的保护,以确保CMS封装的对象没有改变?
发布于 2021-09-17 09:44:55
FWIW你可以使用BouncyCastle只做DER格式化(加上设置版本,一个小的方便),如果你想要的话(也是一个小的方便),在你自己做完所有剩下的工作之后,再加上PEM。示例:
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.security.spec.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.cms.*;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
// sample data and encryption, replace as needed
byte[] input = "testdata".getBytes();
X509Certificate cert = null;
try(InputStream is = new FileInputStream(args[0])){
cert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
}
byte[] skey = new byte[16], snonce = new byte[16];
SecureRandom rand = new SecureRandom(); rand.nextBytes(skey); rand.nextBytes(snonce);
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
aes.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(skey,"AES"), new IvParameterSpec(snonce));
byte[] ctx1 = aes.doFinal(input);
Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
byte[] ctx2 = rsa.doFinal(skey);
// now build the message
byte[] issuer = cert.getIssuerX500Principal().getEncoded();
ASN1Set recips = new DERSet( new KeyTransRecipientInfo(
new RecipientIdentifier(
new IssuerAndSerialNumber(X500Name.getInstance(issuer),cert.getSerialNumber() )),
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption),
new DEROctetString(ctx2) ));
EnvelopedData env = new EnvelopedData (null/*no originfo*/, recips,
new EncryptedContentInfo(CMSObjectIdentifiers.data,
new AlgorithmIdentifier(NISTObjectIdentifiers.id_aes128_CBC,
new DEROctetString(snonce) ),
new DEROctetString(ctx1) ),
new DERSet() /*no attributes*/ );
ContentInfo msg = new ContentInfo(CMSObjectIdentifiers.envelopedData, env);
try(OutputStream os = new FileOutputStream(args[1]) ){
os.write(msg.getEncoded());
}
// or use PemWriter (and a PemObject) if you want PEM发布于 2021-09-24 08:46:29
好吧,我想出了如何调整代码来满足我的需求,这样我就可以分享了。
正在生成收件人:
public RecipientInfo generateRecipientInfo(){
try{
SubjectKeyIdentifier subjectKeyIdentifier = new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey);
RecipientIdentifier recipId = new RecipientIdentifier(new DEROctetString(subjectKeyIdentifier));
return new RecipientInfo(new KeyTransRecipientInfo(recipId, getOAEPAlgorithmIdentifier(),
new DEROctetString(encryptedOaepKey)));
}catch(Exception e){
return null;
}
}适用于RSA的AlgorithIdentifier:
private AlgorithmIdentifier getOAEPAlgorithmIdentifier(){
try{
String digest = "SHA-1";
String mgfDigest = "SHA-1";
JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
OAEPParameterSpec oaepSpec = new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(mgfDigest), PSource.PSpecified.DEFAULT);
AlgorithmIdentifier oaepAlgId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
return oaepAlgId;
}catch (Exception e){
return null;
}
}用于AES CBC的AlgorithmIdentifier (或更改CMSAlgorithm.*之后的GCM )
public AlgorithmIdentifier getAlgorithmIdentifier() {
try{
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES","BC");
algorithmParameters.init(new IvParameterSpec(new byte[keyLength/8]));
return new AlgorithmIdentifier(CMSAlgorithm.AES128_CBC, AlgorithmParametersUtils.extractParameters(algorithmParameters));
}catch (Exception e){
return null;
}
}最后生成CMS封装对象:
public CMSEnvelopedData generate() throws CMSException {
ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
AlgorithmIdentifier encAlgId = aesCryptography.getAlgorithmIdentifier();;
ASN1OctetString encContent = new BEROctetString(encryptedContent);;
recipientInfos.add(generateRecipientInfo());
EncryptedContentInfo eci = new EncryptedContentInfo(
CMSObjectIdentifiers.data,
encAlgId,
encContent);
ContentInfo contentInfo = new ContentInfo(
CMSObjectIdentifiers.envelopedData,
new EnvelopedData(null, new DERSet(recipientInfos), eci, (ASN1Set)null));
return new CMSEnvelopedData(contentInfo);
}https://stackoverflow.com/questions/69193812
复制相似问题