首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用已加密的内容和加密密钥创建CMS封装的数据

使用已加密的内容和加密密钥创建CMS封装的数据
EN

Stack Overflow用户
提问于 2021-09-15 13:09:15
回答 2查看 161关注 0票数 0

tldr:

当我已经用AES和已经用公钥加密的秘密密钥加密内容时,有没有办法创建CMS封装数据?

长版本:

我有一个应用程序,加密和解密数据与AES (CBC和GCM模式)。对称密钥使用RSA密钥对进行加密/解密。当用户请求数据时,我们在后端(Java)对其进行解密,并将其发送到浏览器

通常我们有公钥和私钥,但在某些情况下,要求我们没有私钥,解密应该在浏览器中进行(用户向PFX提供私钥)。这个问题的解决方案是PKI.js,它可以使用PFX和CMS封装数据来解密数据。

问题是,我们已经加密了数据,无法访问我们可以用来构建CMS封装数据的纯数据。

编辑:@dave_thompson_085感谢您的回复!我有一个后续问题。我没有在系统中持有证书,所以我唯一有的就是公钥。有没有办法让你的代码适应这个需求呢?

在你回答之前,我第二次加密数据,只是为了CMS封装的对象。在这段代码中,我只使用了公钥来生成接收器。有没有办法调整你的代码来生成只有公钥的reciepent?我之前的代码:

代码语言:javascript
复制
    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封装的对象没有改变?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-17 09:44:55

FWIW你可以使用BouncyCastle只做DER格式化(加上设置版本,一个小的方便),如果你想要的话(也是一个小的方便),在你自己做完所有剩下的工作之后,再加上PEM。示例:

代码语言:javascript
复制
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
票数 1
EN

Stack Overflow用户

发布于 2021-09-24 08:46:29

好吧,我想出了如何调整代码来满足我的需求,这样我就可以分享了。

正在生成收件人:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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 )

代码语言:javascript
复制
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封装对象:

代码语言:javascript
复制
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);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69193812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档