Сбой шифрования данных с помощью открытого ключа с помощью модуля pkcs11 - PullRequest
2 голосов
/ 28 октября 2019

Я использую пакет Python pkcs11 для доступа к сертификату X.509, хранящемуся на моем Yubikey 5. Доступ к сертификату, открытому и закрытому ключам с помощью pkcs11 Объекты работают хорошо, как подпись и проверка подписи. Однако я не могу понять, почему шифрование с помощью открытого ключа не работает. Вот мой код:

import pkcs11
from pkcs11 import Attribute, ObjectClass, KeyType, util
lib = pkcs11.lib('/usr/lib/x86_64-linux-gnu/pkcs11/onepin-opensc-pkcs11.so')
token = lib.get_token(token_label='PIV Card Holder pin (PIV_II)'
session = token.open(user_pin=pin)
# Getting a private and a public key as pkcs11 Object
private = next(session.get_objects({
    Attribute.CLASS: ObjectClass.PRIVATE_KEY, 
}))
public = next(session.get_objects({
    Attribute.CLASS: ObjectClass.PUBLIC_KEY, 
}))
data = 'Hello, world!'
sig = private.sign(data) # Works!
sig_verif = public.verify(data, sig) # Works!
print("Signature is valid? "+str(sig_verif)) # True
# So far, everything above worked fine.
# ----------
# Now, this is the part that does not work
encrypt_data = public.encrypt(data) # Fails!

Последняя строка выше завершается с ошибкой pkcs11.exceptions.FunctionNotSupported . Я провел некоторое исследование, и это объяснение, которое я нашел, похоже, подразумевает, что эта функция (encrypt) не поддерживается библиотечным файлом openSC (* .so), который я использую. Однако мне трудно поверить, учитывая, что функция подписи работает просто отлично.

Просто чтобы убедиться, что я могу использовать этот конкретный открытый ключ вне контекста сеанса, я попробовал следующий код, используя пакет Crypto:

from Crypto.Cipher import PKCS1_OAEP
public_key = RSA.importKey(public[Attribute.VALUE]) # The content of pkcs11 public key as DER
cipher = PKCS1_OAEP.new(public_key)
encr_data = cipher.encrypt(data) # This works!

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

Затем я попытался использовать функцию расшифровки объекта pkcs11, чтобы попытаться расшифровать данные, сгенерированные с помощью модуля Crypto, описанного выше:

decrypted = private.decrypt(encr_data) # It fails!

Выше не удалось с pkcs11.exceptions.MechanismInvalid ошибка. Я пытался использовать разные механизмы, но все они привели к одной и той же ошибке. Что интересно - кажется, что объект pkcs11 позволяет мне хотя бы вызвать функцию decrypt , не жалуясь, что она не поддерживается.

Еще одна вещь, которую я должен упомянуть. Я проверил свой сертификат и увидел, что в разделе «Расширение -> Использование ключа сертификата» написано:

Critical
Signing
Key Encipherment

Я прочел разницу между шифрованием ключей и шифрованием данных и узнал, что шифрование ключа используется для шифрования секретного (симметричного) ключа вместо данных. Может ли это быть причиной того, что я не могу использовать функцию encrypt для этого сеанса токена?

Любая обратная связь будет принята с благодарностью!

Ответы [ 2 ]

1 голос
/ 30 октября 2019

После довольно обширных исследований и учета ответов этого потока я обнаружил, что шифрование не работает в этом сеансе токена из-за ограничений API OpenSC. На самом деле на странице python-pkcs11 есть таблица совместимости , которая показывает (в виде обычного текста), что OpenSC не поддерживает шифрование, генерацию симметричных ключей, перенос ключей и другие функции. Он полностью поддерживает подпись / проверку и частично поддерживает дешифрование. Если бы я сделал лучший поиск, это сэкономило бы мне много времени.

На самом деле, очень полезно выполнить тест с жестким токеном, используя 'pkcs11-tool', так как этопоказать поддерживаемые функции и механизмы для каждого слота PIV. В моем случае я вызвал его следующим образом:

pkcs11-tool -p $pin -t

и получил следующий отчет:

Using slot 0 with a present token (0x0)
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  seems to be OK
Digests:
  all 4 digest functions seem to work
  MD5: OK
  SHA-1: OK
  RIPEMD160: OK
Signatures (currently only for RSA)
  testing key 0 (PIV AUTH key) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
  testing key 1 (2048 bits, label=SIGN key) with 1 signature mechanism
    RSA-X-509: OK
  testing key 2 (2048 bits, label=KEY MAN key) with 1 signature mechanism -- can't be used to sign/verify, skipping
Verify (currently only for RSA)
  testing key 0 (PIV AUTH key)
    RSA-X-509: OK
    RSA-PKCS: OK
    SHA1-RSA-PKCS: OK
    MD5-RSA-PKCS: OK
    RIPEMD160-RSA-PKCS: OK
  testing key 1 (SIGN key) with 1 mechanism
    RSA-X-509: OK
  testing key 2 (KEY MAN key) with 1 mechanism -- can't be used to sign/verify, skipping
Unwrap: not implemented
Decryption (currently only for RSA)
  testing key 0 (PIV AUTH key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 1 (SIGN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
  testing key 2 (KEY MAN key) 
    RSA-X-509: OK
    RSA-PKCS: OK
No errors

Оттуда мы можем видеть, что расшифровка поддерживается для всех трех занятых слотов, нотолько с механизмами RSA-X-509 и RSA-PKCS (без OAEP).

Теперь я подумываю объединить функции pkcs11-tool и openssl для шифрования данных. Я не разобрался во всех тонкостях такого рода потоков, но я думаю кое-что о такого рода :

  1. (pkcs11-tool) Экспорт сертификата из желаемогоСлот PIV
  2. (openssl) Создать симметричный (например, AES) секретный ключ
  3. (openssl) Шифровать данные с помощью этого секретного ключа
  4. (openssl) Использовать сертификат изшаг 1 для шифрования секретного ключа
  5. Отправьте [симметрично] зашифрованные данные и [асимметрично] зашифрованный секретный ключ получателю
  6. (pkcs11-tool) Расшифруйте секретный ключ на защищенном токене
  7. (openssl) Используйте расшифрованный секретный ключ для расшифровки фактических данных

Похоже, я должен быть в состоянии реализовать такой обходной путь либо в оболочке Linux, используя pkcs11-toolУтилиты и openssl или в Python с использованием библиотек pkcs11 и OpenSSL . Последнее кажется более предпочтительным, если я решу сделать это позже через GUI. Все это кажется довольно низким уровнем, поэтому мне интересно, есть ли более простой способ шифрования / дешифрования данных. Я знаю, что PGP объединяет зашифрованные данные и упакованный секретный ключ в один файл, поэтому конечные пользователи должны выполнить только одну команду на своем конце.

1 голос
/ 30 октября 2019

Извините, но я думаю, что это всего лишь недостаток API. Поскольку шифрование с помощью открытого ключа не требует какой-либо защиты, не имеет смысла внедрять его на Yubikey. Гораздо быстрее экспортировать значения открытого ключа и выполнять шифрование на хосте.

Если честно, Yubikey мог бы быть неплохим и реализовать функциональность в программном обеспечении в библиотеке Ubikey PKCS # 11. Если вы действительно хотите этого, вы можете создать новую библиотеку PKCS # 11 «обертка», которая содержит , которая содержит отсутствующие функциональные возможности в программном обеспечении;все остальные команды, которые Yubikey выполняет , могут быть перенаправлены в исходную библиотеку Yubikey PKCS # 11.

...