Невозможно воспроизвести команду openssl с BouncyCastle - PullRequest
0 голосов
/ 15 января 2019

Уже несколько недель я пытаюсь воспроизвести некоторые команды openssl, используя bouncycastle и java.

После изучения большого количества примеров и множества примеров из Stackoverflow я все еще не могу заставить его работать, поэтому сейчас и прошу помощи.

Команды openssl, которые я должен воспроизвести:

openssl smime -sign -in fileToSign.eml -out signedFile.step2 -passin pass:« password» -binary -nodetach -signer myprivatecert.pem -certfile mypubliccert.pem

Эта первая команда принимает 3 файла: файл для подписи, личный сертификат и открытый сертификат.

Возвращает файл, похожий на:

MIME-версия: 1.0 Content-Disposition: вложение; filename = "smime.p7m" Content-Type: application / x-pkcs7-mime; SMIME типа = знаково-данные; name = "smime.p7m" Content-Transfer-Encoding: base64

MIJAYAYJKoZIhvcNAQcCoIJAUTCCQE0CAQExDzANBglghkgBZQMEAgEFADCCNTUG CSqGSIb3DQEHAaCCNSYEgjUiQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7 CmJvdW5kYXJ5PSItLS0tPUxPR0lQT0xfTUlGXzE1NDY4NTAwNDc4MTYiCi0tLS0t LT1MT0dJUE9MX01JRl8xNTQ2ODUwMDQ3ODE2DQpDb250ZW50LVR5cGU6IHRleHQv WE1MOw0KbmFtZT0iUERBX1A5MDAxMjZfMDA1XzIwMTkwMTA3LjA5MzIwMF8wMDAw MV9JTklULnhtbCI7IGZpbGVuYW1lPSJQREFfUDkwMDEyNl8wMDVfMjAxOTAxMDcu MDkzMjAwXzAwMDAxX0lOSVQueG1sIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGlu ZzogYmFzZTY0DQoNClBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQmxibU52Wkds dVp6MGlWVlJHTFRnaVB6NDhUVWxHVmtGUFNXNW1iMGx1YVhScFlXeGwNClBnbzhT VzVtYjNNK0NqeFdaWEp6YVc5dVBqSXVPVHd2Vm1WeWMybHZiajRLUEVodmNtOWtZ WFJsUGpJd01Ua3RNREV0TURkVU1EazYNCk16UTZNRGM4TDBodmNtOWtZWFJsUGdv OFUyRnBjMmxsU0c5eWIyUmhkR1UrTWpBeE9TMHdNUzB3TjFRd09Ub3pNam93TUR3 ...

Вторая команда, которую я должен использовать:

openssl smime -encrypt -in signedFile.step2 -out encryptedFile.P7M -outform DER -binary anotherpubliccertificate.pub.pem

Эта команда принимает 2 файла: файл, подписанный предыдущей командой, и открытый сертификат, отличный от того, который использовался в предыдущей команде.

Возвращает двоичный файл, зашифрованный файл, созданный на шаге 2.

Любой из примеров, которые я нашел в Интернете, помог мне получить файл, похожий на эти, даже не закрытый.

Я надеюсь, что кто-то может помочь

Редактировать Несколько примеров того, что я пытался или ссылался до сих пор

файл подписи с надувным замком в Java -> Это вернуло подписанный файл, который не соответствует подписанному файлу, созданному с помощью openssl

AES шифрование / дешифрование с провайдером Bouncy Castle -> Опять же, это не работает, результат не соответствует зашифрованному файлу, который я генерирую с openssl

https://studylibfr.com/doc/3898805/cryptographie-avec-bouncy-castle---zenk -> Выполняли весь урок, но не получили ожидаемого результата

X509 RSA надувной замок подписывает и проверяет простой текст на Java -> Подписанный файл тоже не соответствует

https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/CreateSignedMultipartMail.java -> Этот класс генерирует что-то похожее на то, что я пытаюсь получить, но я не смог проверить его правильность, так как я должен зашифровать его и все равно не могу заставить шифрование работать

https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/ReadSignedMail.java -> То же, что и в предыдущем классе

https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/SendSignedAndEncryptedMail.java -> Этот метод шифрования не возвращает тот же результат, что и openssl, поэтому он не работает

Конечно, я пытался продолжать работать над этими примерами классов из bouncycastle, но безуспешно.

Любая помощь будет оценена

Редактировать 2 Ответ на следующий вопрос Подписать и зашифровать файл с помощью S / MIME возвращает файл в кодировке Base64, который может соответствовать тому, что я генерирую с openssl. Но проблема в том, что мой входной файл составляет около 25 КБ, а сгенерированный подписанный файл - только 3 КБ, я не понимаю, почему, я заметил, что в этой строке:

CMSTypedData content = new CMSProcessableByteArray(buffer);
CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();

метод getEncoded () возвращает мне байтовый массив, намного меньший, чем буфер, который я отправляю в CMSSignedData.

Кто-нибудь знает причину?

1 Ответ

0 голосов
/ 16 января 2019

Для подписания вы были довольно близки с org.bouncycastle.mail.smime.examples.CreateSignedMultipartMail за исключением того, что

  • это делает multipart data , что openssl smime не делает; начать с CreateSignedMail вместо

  • он выполняет многочастную подпись , то есть прозрачную подпись, для которой openssl smime также используется по умолчанию, но -nodetach меняет ее на встроенную, то есть инкапсулированную

  • включает полную цепочку сертификатов, но самогенерируемую с длиной только 2, тогда как почти все «настоящие» сертификаты длиннее, тогда как openssl по умолчанию включает только сертификат подписавшего

  • по умолчанию он использует некоторые подписанные атрибуты, отличные от openssl

Для шифрования (или, точнее, для охвата) openssl smime -outform der, несмотря на название, вообще не делает SMIME, он делает CMS (первоначально и до сих пор также известный как PKCS7). Bouncy использует все преимущества OO Java, чтобы поместить CMS и SMIME, которые очень похожи, но не одинаковы, в разные классы, которые связаны, но не одинаковы, поэтому вам нужен класс (ы) CMS.

Соединяя их вместе (плюс минимальный тестовый жгут), я представляю вам:

    // for test, (own) signing key+certchain and (peer) encryption cert in file
    KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(args[0]),args[1].toCharArray());
    PrivateKey signkey = (PrivateKey) ks.getKey(args[2], args[1].toCharArray());
    Certificate[] signcert = ks.getCertificateChain(args[2]);
    Certificate encrcert = ks.getCertificate(args[3]);
    // and data in file
    byte[] data = Files.readAllBytes(new File(args[4]).toPath());

    // adapted from org.bouncycastle.mail.smime.examples.CreateSignedMail 
    // OpenSSL uses this rather silly capability list; may not be needed 
    SMIMECapabilityVector       caps = new SMIMECapabilityVector();
    caps.addCapability(SMIMECapability.aES256_CBC);
    caps.addCapability(SMIMECapability.aES192_CBC);
    caps.addCapability(SMIMECapability.aES128_CBC);
    caps.addCapability(SMIMECapability.dES_EDE3_CBC);
    caps.addCapability(SMIMECapability.rC2_CBC, 128);
    caps.addCapability(SMIMECapability.rC2_CBC, 64);
    caps.addCapability(SMIMECapability.dES_CBC);
    caps.addCapability(SMIMECapability.rC2_CBC, 40);
    ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
    signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
    // Bouncy default adds RFC6211 in addition to standard ctype, stime, mdgst
    // and changing this is complicated; recipient _should_ ignore unneeded attr

    SMIMESignedGenerator gen = new SMIMESignedGenerator();
    gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder()//.setProvider("BC") not needed
        .setSignedAttributeGenerator(new AttributeTable(signedAttrs))
        .build("SHA1withRSA", signkey, (X509Certificate) signcert[0]) ); 
    // change sigalg if key not RSA and/or want better hash
    // OpenSSL by default includes only signer cert; recipient may want more
    gen.addCertificates(new JcaCertStore (Arrays.asList (new Certificate[]{signcert[0]}) ));

    MimeBodyPart msg = new MimeBodyPart();
    msg.setText(new String(data, "ISO-8859-1")); // OpenSSL doesn't know charsets
    ByteArrayOutputStream temp = new ByteArrayOutputStream();
    gen.generateEncapsulated(msg).writeTo(temp); // OpenSSL -nodetach is encapsulated
    // Bouncy uses BER here (unlike OpenSSL DER) 
    // and I don't see a simple way to change it but it _should_ not matter 
    byte[] signedblob = temp.toByteArray();

    // now CMS (not SMIME) enveloping
    CMSEnvelopedDataGenerator edgen = new CMSEnvelopedDataGenerator();
    edgen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator((X509Certificate) encrcert));
    CMSEnvelopedData edmsg = edgen.generate( new CMSProcessableByteArray(signedblob),
            new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).build() );
    byte[] encrblob = edmsg.toASN1Structure().getEncoded(ASN1Encoding.DER); // OpenSSL is DER though std doesn't require it

    // for test, write to a file
    Files.write(new File(args[5]).toPath(), encrblob);

Вкл, и «кто-нибудь знает причину»

CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();

меньше, чем содержание? См. javadoc - с encapsulate (второй параметр), установленным на false, вы сказали, что не включает содержимое в подпись (точнее SignedData), и это сделал, как вы требовали.

...