将cms包装到MimeMessage中

时间:2019-07-20 09:45:56

标签: android bouncycastle

是否存在让MimeMessage附加cms签名数据的有效示例?

我知道BouncyCastle随SMIMEEnvelopedGenerator一起提供,但我正在从卡中读取私钥,因此使用cms而不是smime。 我设法以签名数据的形式发送邮件,但是在解析签名消息的内容时返回空。

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] data = "Hello World!".getBytes();
            //start sign

            List certList = new ArrayList();
            certList.add(cert);
            Store certs = new JcaCertStore(certList);

            CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
            ContentSigner sha1Signer =
                    new JcaContentSignerBuilder(
                            "SHA256withRSA").setProvider("MyProvider").build((PrivateKey) key);
            JcaSignerInfoGeneratorBuilder signBuilder =
                    new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());

            gen.addSignerInfoGenerator(signBuilder.build(sha1Signer, (X509Certificate) cert));
            gen.addCertificates(certs);

            bos.reset();
            OutputStream sigOut = gen.open(bos, true);
            sigOut.write(data);
            sigOut.close();

            Log.e(TAG, " signature: " + new String(bos.toByteArray()));

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            try {
                ASN1InputStream asn1 = new ASN1InputStream(bos.toByteArray());
                DEROutputStream dos = new DEROutputStream(out);
                dos.writeObject(asn1.readObject());
                Log.e(TAG, "asn1: " + new String(out.toByteArray()));
            } catch (IOException e1) {
                throw new SignatureException("Failed to generate signature", e1);
            }

            byte[] base64Sig = Base64.encode(out.toByteArray(), Base64.DEFAULT);
            Log.e(TAG, "string encodedSig: \n" + new String(base64Sig));
            CryptoUtils.parseContentType(out.toByteArray());

            MimeBodyPart part = new MimeBodyPart(new InternetHeaders(), base64Sig);
            part.addHeader("Content-Type", "application/pkcs7-mime; name=smime.p7m; smime-type=signed-data");
            part.addHeader("Content-Disposition", "attachment; filename=smime.p7m");
            part.addHeader("Content-Description", "S/MIME Cryptographic Signed Data");
            part.addHeader("Content-Transfer-Encoding", "base64");

            bos.reset();
            part.writeTo(bos);
            Log.e(TAG, "part: " + new String(bos.toByteArray()));

            MimeMessage msg = new MimeMessage(getSession());
            msg.setFrom(new InternetAddress("test@mail.com"));
            msg.setRecipients(Message.RecipientType.TO, "test2@mail.com");
            msg.setSentDate(new Date());
            msg.setSubject("Subject");
            msg.setContent(part, part.getContentType());

            //end sign

            bos.reset();
            msg.writeTo(bos);
            Log.e(TAG, "final: " + new String(bos.toByteArray()));

所以我Transport.send(msg),但是解密内容时返回的是空而不是Hello world

1 个答案:

答案 0 :(得分:0)

最终解决了它。您需要使用文本创建模仿,并在模仿而不是文本上签名。下面的快照器可供参考:

            MimeBodyPart m = new MimeBodyPart();
            m.setText("Hello World!");

            MimeMultipart mimeMultipart = new MimeMultipart();
            mimeMultipart.addBodyPart(m);

            MimeMessage mm = new MimeMessage(getSession());
            mm.setContent(mimeMultipart);
            bos.reset();
            mm.writeTo(bos);
            Log.e(TAG, "mm: " + new String(bos.toByteArray()));

            List certList = new ArrayList();
            certList.add(cert);
            Store certs = new JcaCertStore(certList);

            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
            ContentSigner sha1Signer =
                    new JcaContentSignerBuilder(
            "SHA256withRSA").setProvider("Your Provider").build((PrivateKey) key);
            JcaSignerInfoGeneratorBuilder signBuilder =
                    new JcaSignerInfoGeneratorBuilder(new 
            JcaDigestCalculatorProviderBuilder().setProvider("BC").build());

            gen.addSignerInfoGenerator(signBuilder.build(sha1Signer, (X509Certificate) 
            cert));
            gen.addCertificates(certs);

            CMSSignedData signedData = gen.generate(new 
            CMSProcessableByteArray(bos.toByteArray()), true);
            Log.e(TAG, " signature: " + new String(signedData.getEncoded()));

然后将签名的数据附加到模仿消息中,如下所示:

            msg.setDataHandler(new DataHandler(new 
            ByteArrayDataSource(signedData.getEncoded()

还要添加相关的标题:

            msg.addHeader("Content-Type", "application/pkcs7-mime; name=smime.p7m; 
            smime-type=signed-data");
            msg.addHeader("Content-Disposition", "attachment; filename=smime.p7m");
            msg.addHeader("Content-Description", "S/MIME Cryptographic Signed Data");