Шифрование/дешифрование с помощью bouncycastle-java и RSAES-OAEP

Я не эксперт в шифровании, но я пытаюсь создать CMSEnvelopedDataGenerator с bouncycastle 1.67, где ключ сеанса зашифрован с помощью RSAES-OAEP (1.2.840.113549.1.1.7)

Пока мой код выглядит так:

 CMSEnvelopedDataGenerator envelopedGenerator = new CMSEnvelopedDataGenerator();
 
 JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
 OAEPParameterSpec oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);

 AlgorithmIdentifier algorithmIdentifier;    
 algorithmIdentifier = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
 JceKeyTransRecipientInfoGenerator recipent = new JceKeyTransRecipientInfoGenerator(receiverCert, algorithmIdentifier).setProvider("BC");    
 
 # encrypt
 CMSEnvelopedData envelopedData;
 envelopedData = envelopedGenerator.generate(
     new CMSProcessableByteArray(encodedSignedData),  
     new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build()
 )

Он проходит, но когда я проверяю его через openssl asn1parse, я вижу

115:d=6  hl=2 l=   9 prim: OBJECT            :rsaesOaep
126:d=6  hl=2 l=  47 cons: SEQUENCE
128:d=7  hl=2 l=  15 cons: cont [ 0 ]
130:d=8  hl=2 l=  13 cons: SEQUENCE
132:d=9  hl=2 l=   9 prim: OBJECT            :sha256
143:d=9  hl=2 l=   0 prim: NULL
145:d=7  hl=2 l=  28 cons: cont [ 1 ]
147:d=8  hl=2 l=  26 cons: SEQUENCE
149:d=9  hl=2 l=   9 prim: OBJECT            :mgf1
160:d=9  hl=2 l=  13 cons: SEQUENCE
162:d=10 hl=2 l=   9 prim: OBJECT            :sha256

а затем шестнадцатеричный дамп. В моем справочном файле это выглядит так:

115:d=6  hl=2 l=   9 prim: OBJECT            :rsaesOaep
126:d=6  hl=2 l=  43 cons: SEQUENCE
128:d=7  hl=2 l=  13 cons: cont [ 0 ]
130:d=8  hl=2 l=  11 cons: SEQUENCE
132:d=9  hl=2 l=   9 prim: OBJECT            :sha256
143:d=7  hl=2 l=  26 cons: cont [ 1 ]
145:d=8  hl=2 l=  24 cons: SEQUENCE
147:d=9  hl=2 l=   9 prim: OBJECT            :mgf1
158:d=9  hl=2 l=  11 cons: SEQUENCE
160:d=10 hl=2 l=   9 prim: OBJECT            :sha256

В строке 143 в моем файле есть строка

143:d=9  hl=2 l=   0 prim: NULL

Я не уверен, откуда это взялось.

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

 exception unwrapping key: bad padding: unable to decrypt block

Caused by: org.bouncycastle.cms.CMSException: exception unwrapping key: bad padding: unable to decrypt block
 at org.bouncycastle.cms.jcajce.JceKeyTransRecipient.extractSecretKey(Unknown Source)
 at org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient.getRecipientOperator(Unknown Source)
 at org.bouncycastle.cms.KeyTransRecipientInformation.getRecipientOperator(Unknown Source)
 at org.bouncycastle.cms.RecipientInformation.getContentStream(Unknown Source)

Caused by: org.bouncycastle.operator.OperatorException: bad padding: unable to decrypt block
at org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper.generateUnwrappedKey(Unknown Source)

Caused by: org.bouncycastle.jcajce.provider.util.BadBlockException: unable to decrypt block
at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.getOutput(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)

Caused by: org.bouncycastle.crypto.InvalidCipherTextException: data wrong
at org.bouncycastle.crypto.encodings.OAEPEncoding.decodeBlock(Unknown Source)
at org.bouncycastle.crypto.encodings.OAEPEncoding.processBlock(Unknown Source)

Я надеюсь, что это не так много, этого не хватает.

Редактировать:

С моим неправильно сгенерированным файлом recipient.getKeyEncryptionAlgorithm().getParameters() приводит к

[[0][2.16.840.1.101.3.4.2.1, NULL], [1][1.2.840.113549.1.1.8, [2.16.840.1.101.3.4.2.1, NULL]]]

правильный файл в

[[0][2.16.840.1.101.3.4.2.1], [1][1.2.840.113549.1.1.8, [2.16.840.1.101.3.4.2.1]]]

Откуда берутся эти неправильные NULL значения SHA-256.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
1 254
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы упоминаете только один «лишний» NULL в сообщении, созданном BC, но на самом деле их два, причем второй в первой строке вы исключили из опубликованных вами данных. Поля (разной) длины в вашем посте, а также отображение getParameters() ясно показывают это.

Эти NULL не являются неправильными.

Эти значения NULL являются параметрами алгоритмов хеширования в структуре параметров OAEP и требуются стандартом. Из RFC 3447 = PKCS1v2.1, которая является первой версией, включающей SHA-2 (в 2003 г., сразу после FIPS 186-2 в 2002 г.) в A.2.1:

The parameters field ... shall have a value of type RSAES-OAEP-params:

      RSAES-OAEP-params ::= SEQUENCE {
          hashAlgorithm     [0] HashAlgorithm    DEFAULT sha1,
          maskGenAlgorithm  [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
          pSourceAlgorithm  [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty
      }
...
         HashAlgorithm ::= AlgorithmIdentifier {
            {OAEP-PSSDigestAlgorithms}
         }

         OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
             { OID id-sha1 PARAMETERS NULL   }|
             { OID id-sha256 PARAMETERS NULL }|
             { OID id-sha384 PARAMETERS NULL }|
             { OID id-sha512 PARAMETERS NULL },
             ...  -- Allows for future expansion --
         }
...
         MaskGenAlgorithm ::= AlgorithmIdentifier {
            {PKCS1MGFAlgorithms}
         }
         PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
             { OID id-mgf1 PARAMETERS HashAlgorithm },
             ...  -- Allows for future expansion --
         }

Обратите внимание, что обе спецификации хэша — внешний хеш для метки и внутренний хеш в параметрах MGF1 — определяются информационным набором HashAlgorithm, и все определенные значения в этом наборе, включая SHA-256, имеют параметры, явно равные NULL, а не опущенные, поскольку общие разрешения X.509 ASN.1 (сравните RFC5280 4.1.1.2, в котором используется старая нотация pre-infoset).

Обратите внимание, что то же самое верно для PSS в A.2.3 и с немного большим набором алгоритмов хеширования для DigestInfo в RSASSA-PKCS1-v1_5 в A.2.4. Это и эквивалентные положения в версии 2.0 (за исключением PSS, которого не было в версии 2.0, и с немного другими обозначениями) могут быть реакцией на PKCS1v1.5 в 10.1.2, только делая параметры подписи DigestInfo «должными» (нижний регистр даже после 2119 года, предположительно потому, что это был текст RSALabs, а не IETF), что привело к различиям в реализациях, из-за которых подписи, которые на самом деле были правильными, иногда не проверялись, что считалось плохой вещью, нуждающейся в исправлении.

Таким образом, ваш «справочный» файл технически нарушает стандарт. Однако, поскольку эти хеш-алгоритмы на самом деле не используют параметры — вот почему они кодируются с помощью NULL — BouncyCastle может легко быть терпимым и принимать опущенный регистр. Я протестировал действующую в остальном структуру, и она работает в обоих направлениях. (Меня не удивит, если он будет работать даже с каким-то неподходящим значением, например, с вставленной туда строкой октетов, но я этого не проверял.)

Даже если кодировка параметров была неправильной, это не вызовет исключения, которое у вас есть - это будет либо явная ошибка декодирования/анализа, например, «отсутствует обязательное поле», либо ошибка создания экземпляра, например, «недопустимые параметры для алгоритма x». При отсутствии ошибок «плохое заполнение» вызвано поврежденными, подделанными или иным образом неправильными данными (что в среде CMS маловероятно) или несоответствием ключей.

Убедитесь, что вы используете совпадающие ключи.

Спасибо за подробный ответ. После дальнейшей отладки я обнаружил ошибку при расшифровке в сочетании с несколькими получателями.

Skully 14.12.2020 10:43

Другие вопросы по теме