Проверка подписанного лицензионного ключа с открытым ключом RSA в Python - PullRequest
0 голосов
/ 26 февраля 2019

Отказ от ответственности: я ужасен в криптографии и очень мало понимаю о RSA или криптографической проверке.

Мне нужно проверить подписанную лицензию в Python.Я использовал «RSA PKCS1 v1.5 padding с дайджестом SHA256».Исходная информация состоит в том, что я пытаюсь распространять программное обеспечение с https://keygen.sh.

По сути, двоичное программное обеспечение установлено на сервере и проверяет подлинность файла лицензии, хранящегося на сервере.Для этого у программного обеспечения есть доступ к моему открытому ключу RSA.У меня есть фрагмент кода, работающий в Node.js, взятый из официальной документации keygen , и я пытаюсь перенести его на Python, но безуспешно.Я решил использовать библиотеку cryptodome, но я открыт для других опций.

Вот рабочий фрагмент кода в Node.js:

const crypto = require('crypto')

const public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmwlw+mDo2ZVBlRXa7Em\ncj7cVrlwnwrIPC+Ij5KpltadJfwvRFvCr37USJvkc+FIND2dKk2mmbY32cvtxl3F\nYLpjRwwlFuajbP8ZEdJl1YJyJDnLlKHWEfTSvTzZhpT939yjuBKoZ9A+wiIQ9tzY\nF/ytb9zwPkOF7/XmPAaukah5xRgwsb3fo7E0CsBQuHZxFX83+nfdZ/60MWpSCWL6\nAjNWDEmoLFEHVRm69+lwXTW51wojfurZy/wUw42sciHLV5A8mz7gJJGO5y+sGzzD\nM5VxtmLz51Fl1Rl3fMzUAjPK77i9UDWo11EuNPrzMAgjmuuMLfpIDMlMR3n/ZsW7\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
const key = 'somerandomkey'
const encodedSignature = "oMTrvIz3IX4kre5UTzvkzCn712wulPvl9knSYBduYcGsX2W703zWMC9ZVepDytxLdpUIiCUtx6wx5OzmLx3rTzgaKqptrbf2wYHrCIPBgrhcHdJ3fLJRh8ASC_NdLK6i1jC_bEAq84d7QNLlTPC20aCmNLdxEJFy-DValGG0iFdxx6n6-Vp5oL8jSyWubAvBSqEQ4ubptcYirxpbDdC4DRpNzBuA48DGxWg6Pxq5HdGZWKS05iohNlrFkW-K8NJYHuLKszT0FN5UWcghx1oklagCm72aDvXm3CzKL2id7yL78X_V69JYsExx3fjRsU0pUe-f5lzKLB_HLTAdc0e1gQ=="

const verifier = crypto.createVerify('sha256')
verifier.write(key)
verifier.end()

const ok = verifier.verify(public_key, encodedSignature, 'base64')
if (ok) {
  console.log('License key is valid!')
} else {
  console.log('License key is invalid!')
}

Запуск этого фрагментакод (nodejs verify.js) печатает License key is valid!.

А вот код ошибки в Python:

import base64

# pip install cryptodome
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import Crypto.Signature.pkcs1_15
import Crypto.Util.Padding

public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmwlw+mDo2ZVBlRXa7Em\ncj7cVrlwnwrIPC+Ij5KpltadJfwvRFvCr37USJvkc+FIND2dKk2mmbY32cvtxl3F\nYLpjRwwlFuajbP8ZEdJl1YJyJDnLlKHWEfTSvTzZhpT939yjuBKoZ9A+wiIQ9tzY\nF/ytb9zwPkOF7/XmPAaukah5xRgwsb3fo7E0CsBQuHZxFX83+nfdZ/60MWpSCWL6\nAjNWDEmoLFEHVRm69+lwXTW51wojfurZy/wUw42sciHLV5A8mz7gJJGO5y+sGzzD\nM5VxtmLz51Fl1Rl3fMzUAjPK77i9UDWo11EuNPrzMAgjmuuMLfpIDMlMR3n/ZsW7\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
license_key = b'somerandomkey'

encoded_license_signature = """oMTrvIz3IX4kre5UTzvkzCn712wulPvl9knSYBduYcGsX2W703zWMC9ZVepDytxLdpUIiCUtx6wx5OzmLx3rTzgaKqptrbf2wYHrCIPBgrhcHdJ3fLJRh8ASC_NdLK6i1jC_bEAq84d7QNLlTPC20aCmNLdxEJFy-DValGG0iFdxx6n6-Vp5oL8jSyWubAvBSqEQ4ubptcYirxpbDdC4DRpNzBuA48DGxWg6Pxq5HdGZWKS05iohNlrFkW-K8NJYHuLKszT0FN5UWcghx1oklagCm72aDvXm3CzKL2id7yL78X_V69JYsExx3fjRsU0pUe-f5lzKLB_HLTAdc0e1gQ=="""
license_signature = base64.b64decode(encoded_license_signature)
# Padding: none of these solutions work
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='pkcs7')
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='iso7816')
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='x923')
# Custom zero-padding (doesn't work either)
#license_signature = (8 - len(license_signature) % 8)*bytes([0]) + license_signature
#license_signature = license_signature + (8 - len(license_signature) % 8)*bytes([0])

rsa_public_key = RSA.import_key(public_key)
signature = Crypto.Signature.pkcs1_15.new(rsa_public_key)

license_hash = SHA256.new(data=license_key)
print(signature.verify(license_hash, license_signature))

Запуск этого фрагмента кода (python3 verify.py) вызывает ошибку:

Traceback (most recent call last):
  File "verify.py", line 30, in <module>
    print(signature.verify(license_hash, license_signature))
  File "/home/user/venvs/tutor/lib/python3.6/site-packages/Crypto/Signature/pkcs1_15.py", line 111, in verify
    raise ValueError("Invalid signature")
ValueError: Invalid signature

Это соответствует ошибке длины подписи :

# Step 1
if len(signature) != k:
    raise ValueError("Invalid signature")

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

Traceback (most recent call last):
  File "verify.py", line 30, in <module>
    print(signature.verify(license_hash, license_signature))
  File "/home/user/venvs/tutor/lib/python3.6/site-packages/Crypto/Signature/pkcs1_15.py", line 137, in verify
    raise ValueError("Invalid signature")
ValueError: Invalid signature

Есть идеи, как это решить?При необходимости я готов использовать что-то отличное от криптодома.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Я основатель Keygen.Это отсутствие надлежащей документации с моей стороны, которую я исправлю.Как и Мартен упомянул , подписанное содержимое лицензионного ключа (который состоит из 2 частей: полезная нагрузка ключа и его подпись) кодируется base64url с использованием RFC 4648 , URL-версии base64.который поддерживается в большинстве языков программирования (но не всегда).Эта схема кодирования base64url немного отличается от обычной кодировки base64, как обрисовано в общих чертах в ответе Мартена.

Большинство языков программирования будут иметь отдельную функцию для декодирования закодированных значений URL base64, но в противном случае, как обрисовывает в общих чертах Мартен в своем ответе,Вы можете просто заменить все символы "-" base64 на "+", а все символы "_" на "/".

Вот полный пример проверки подписанного лицензионного ключас RSA-SHA256 с использованием отступа PKCS1 v1.5:

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
import base64

# This should be your Keygen account's public key
PUBLIC_KEY = \
"""-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmwlw+mDo2ZVBlRXa7Em
cj7cVrlwnwrIPC+Ij5KpltadJfwvRFvCr37USJvkc+FIND2dKk2mmbY32cvtxl3F
YLpjRwwlFuajbP8ZEdJl1YJyJDnLlKHWEfTSvTzZhpT939yjuBKoZ9A+wiIQ9tzY
F/ytb9zwPkOF7/XmPAaukah5xRgwsb3fo7E0CsBQuHZxFX83+nfdZ/60MWpSCWL6
AjNWDEmoLFEHVRm69+lwXTW51wojfurZy/wUw42sciHLV5A8mz7gJJGO5y+sGzzD
M5VxtmLz51Fl1Rl3fMzUAjPK77i9UDWo11EuNPrzMAgjmuuMLfpIDMlMR3n/ZsW7
XwIDAQAB
-----END PUBLIC KEY-----"""

# This should be the license key that you're cryptographically verifying
LICENSE_KEY = \
"""c29tZXJhbmRvbWtleQ==.oMTrvIz3IX4kre5UTzvkzCn712wulPvl9knSYBduYcGsX2W703zWMC9ZVepDytxLdpUIiCUtx6wx5OzmLx3rTzgaKqptrbf2wYHrCIPBgrhcHdJ3fLJRh8ASC_NdLK6i1jC_bEAq84d7QNLlTPC20aCmNLdxEJFy-DValGG0iFdxx6n6-Vp5oL8jSyWubAvBSqEQ4ubptcYirxpbDdC4DRpNzBuA48DGxWg6Pxq5HdGZWKS05iohNlrFkW-K8NJYHuLKszT0FN5UWcghx1oklagCm72aDvXm3CzKL2id7yL78X_V69JYsExx3fjRsU0pUe-f5lzKLB_HLTAdc0e1gQ=="""

# Split license key to obtain key and signature, then decode urlbase64 encoded values
enc_key, enc_sig = LICENSE_KEY.split(".")
key = base64.urlsafe_b64decode(enc_key)
sig = base64.urlsafe_b64decode(enc_sig)

# Verify the key's signature
pub_key = RSA.importKey(PUBLIC_KEY)
verifier = PKCS1_v1_5.new(pub_key)
digest = SHA256.new(data=key)

print(
  verifier.verify(digest, sig)
)

Я обновил документацию Keygen, чтобы прояснить все эти вещи, а также предоставить лучшие примеры того, как криптографически проверять лицензию.

0 голосов
/ 27 февраля 2019

Ваша подпись в base64url вместо стандартной base64.Я предполагаю, что последний является виновником.Поэтому вам нужно заменить - на + и _ на /.Или, конечно, используйте декодер base64url.

...