.NET Core 3 не может загрузить закрытый ключ ECC - PullRequest
6 голосов
/ 17 июня 2019

Благодаря Загружая закрытый ключ ECC в .NET , я могу загрузить закрытые ключи ECC в .NET Core 3 и выполнять с ними задачи подписи.

Я, однако, натолкнулся на один ключ, который не может быть загружен ECDSA.ImportPrivateKey. Что странно, так это то, что при просмотре openssl ключевые байты меняются на то, что .NET Core 3 может понять.

Код для импорта неисправного закрытого ключа (это фактический ключ, который не работает):

ecdsa = ECDsa.Create();
var pem = "MHYCAQEEH5t2Xlmsw5uqw3W9+/3nosFi6i3V901uW6ZzUpvVM0qgCgYIKoZIzj0DAQehRANCAASck2UuMxfyDYBdJC0mHNeToqMBhJuMZYSgkUNbK/xzD7e3cwr5okPx0pZdSMfDmyi1dBujtIIxFK9va1bdVAR9";
var derArray = Convert.FromBase64String(pem);
ecdsa.ImportECPrivateKey(derArray, out _);

Сбой вызова ImportECPrivateKey с System.Security.Cryptography.CryptographicException : ASN1 corrupted data внутри System.Security.Cryptography.EccKeyFormatHelper.FromECPrivateKey(ReadOnlyMemory`1 keyData, AlgorithmIdentifierAsn& algId, ECParameters& ret)

Исходный файл PEM выглядит так:

$ cat private_key_cert_265.pem
-----BEGIN EC PRIVATE KEY-----
MHYCAQEEH5t2Xlmsw5uqw3W9+/3nosFi6i3V901uW6ZzUpvVM0qgCgYIKoZIzj0D
AQehRANCAASck2UuMxfyDYBdJC0mHNeToqMBhJuMZYSgkUNbK/xzD7e3cwr5okPx
0pZdSMfDmyi1dBujtIIxFK9va1bdVAR9
-----END EC PRIVATE KEY-----

openssl преобразует закрытый ключ во что-то другое:

$ openssl ec -in private_key_cert_265.pem
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIACbdl5ZrMObqsN1vfv956LBYuot1fdNblumc1Kb1TNKoAoGCCqGSM49
AwEHoUQDQgAEnJNlLjMX8g2AXSQtJhzXk6KjAYSbjGWEoJFDWyv8cw+3t3MK+aJD
8dKWXUjHw5sotXQbo7SCMRSvb2tW3VQEfQ==
-----END EC PRIVATE KEY-----

Используя эту форму файла PEM, .NET Core 3 может импортировать закрытый ключ.

Мой вопрос: что происходит; Почему openssl меняет закрытый ключ на другой формат (как узнать, какой формат какой?) И почему .NET Core 3 может понимать один формат, а не другой?

1 Ответ

2 голосов
/ 17 июня 2019

Исходный ключ неверно отформатирован. Закрытое значение S не было правильно дополнено левым полем. Значение S передается как беззнаковое целое число с прямым порядком байтов в пределах строки октетов ASN.1. Эта строка октетов (байтовый массив) должна иметь тот же размер, что и размер ключа в байтах, по определению. Это означает, что для используемой 256-битной кривой должно быть 32 байта (secp256r1, известный под разными именами).

Итак, ваш код и код .NET верны. OpenSSL кажется более либеральным, что он принимает, но он записывает значение S, как и должно быть.


Ниже приведено начальное значение закрытого ключа, взятое из здесь :

SEQUENCE (4 elem)
  INTEGER 1
  OCTET STRING (31 byte) 9B765E59ACC39BAAC375BDFBFDE7A2C162EA2DD5F74D6E5BA673529BD5334A
  [0] (1 elem)
    OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
  [1] (1 elem)
    BIT STRING (520 bit) 0000010010011100100100110110010100101110001100110001011111110010000011…

а вот исправленный OpenSSL:

SEQUENCE (4 elem)
  INTEGER 1
  OCTET STRING (32 byte) 009B765E59ACC39BAAC375BDFBFDE7A2C162EA2DD5F74D6E5BA673529BD5334A
  [0] (1 elem)
    OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
  [1] (1 elem)
    BIT STRING (520 bit) 0000010010011100100100110110010100101110001100110001011111110010000011…

и обратите внимание на размер значения OCTET STRING и предшествующего нуля.


Этот закрытый ключ теперь, конечно, взломан. Обратите внимание, что существует меньшая вероятность отсутствия двух 00 байтов или трех (и т. Д.).

...