Импорт открытого ключа PKCS11 в BouncyCastle - PullRequest
0 голосов
/ 12 марта 2019

Я использую HSM для генерации пары открытого / закрытого эллиптического ключа с помощью команд PKCS11, но мне нужно использовать открытый ключ в BouncyCastle.

Я могу прочитать атрибут EC_POINT в формате DER, но не могу понять, как импортировать его в BouncyCastle.

Это мой атрибут EC_POINT: CKA_EC_POINT: 04-39-04-ED-48-AE-D9-F8-02-CA-80-E1-1C-F2-3D-C9-C4-7D-B4-C5-9E-D2-53-A6- FE-27-D7-12-EF-C3-7F-2D-FC-D2-D0-31-62-8F-АФ-60-19-E4-33-0F-63-A7-E4-95-33- 0C-0D-D5-94-6C-92-B9-44-D8-2B * * +1005

Это мое рабочее решение (спасибо Дэйву)

public ECPublicKeyParameters GetPubKeyFromParms(string curve, string pub) {
    var pc = ToByteArray(pub);
    var x9ecpar = ECNamedCurveTable.GetByName(curve);
    var ecdp = new ECDomainParameters(x9ecpar.Curve, x9ecpar.G, x9ecpar.N);
    var basePoint = lsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(null, ecdp, pc));
    var subinfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(basePoint);
    var publicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(subinfo);
    return publicKey;
}

Преобразование подписи из формата PKCS11 в формат BouncyCastle:

var r = signature.Take(signature.Length / 2).ToArray();
var s = signature.Skip(signature.Length / 2).ToArray();
var dersignature = new Org.BouncyCastle.Asn1.DerSequence(
                    new Org.BouncyCastle.Asn1.DerInteger(new Org.BouncyCastle.Math.BigInteger(1, r)),
                    new Org.BouncyCastle.Asn1.DerInteger(new Org.BouncyCastle.Math.BigInteger(1, s))
                ).GetDerEncoded();

1 Ответ

1 голос
/ 15 марта 2019

Хорошо, это действительно выглядит как (DER) OCTET STRING (тег 04, длина 39 hex), содержащий точку в стандартном (X9.62 / SEC1 et seq) несжатом формате (первый октет 04) для 28-октетного кода. (224-битная) кривая. Это кажется мне глупым, поскольку все известные мне стандартные структуры ASN.1 помещают (точечный или другой) pubkey в BIT STRING и включают метаданные, но, очевидно, это известно или, по крайней мере, о нем слышно, потому что asn1.x9.X9ECPoint имеет конструктор для него. (Для краткости и форматирования я опускаю внешний пакет org.bouncycastle, который применяется ко всему.)

Чтобы использовать точку, вам нужно указать, на какой она кривой; Мне известны две 224-битные кривые (точнее, наборы параметров), стандартизированные SECG и X9, secp224 {k1, r1}, последняя из которых (только) принята NIST в FIPS 186-2 + как P-224, и два стандартизированы TeleTrusT как brainpool224 {r1, t1}. Они доступны встроенными от asn1.x9.ECNamedCurveTable или jce.ECNamedCurveTable. Может быть любое количество нестандартных кривых, которые AFAICT вам придется создавать самостоятельно. Если вы не знаете, на какой кривой находится ваша несжатая точка, вы можете с точной точностью угадать, проверяя, удовлетворяет ли она уравнениям кривых-кандидатов; Я слишком ленив, чтобы сделать это для вас. (Сжатую точку будет гораздо сложнее угадать, возможно, невозможно.)

Учитывая кривую (из набора параметров или прямой), преобразуйте DER в ASN1OctetString с ASN1OctetString.getInstance(ASN1Primitive.fromByteArray(byte[])) или просто ASN1OctetString.getInstance(Object/*byte[]*/), который делает первое для вас, и тогда вы можете напрямую построить X9ECPoint и в зависимости от того, с какими API вы хотите его использовать, либо вызовите .getPoint для преобразования в math.ec.ECPoint, либо создайте связанные (более сложные) структуры, такие как crypto.params.ECPublicKeyParameters.


Добавлено в ответ на комментарий, так как это довольно долго, плюс несколько изменяет мой ответ:

Я не осознавал, что вы используете dotNET; Мой опыт связан с Java-версией Bouncy, и я впечатлен тем, что две версии достаточно точно отслеживают ваш код, даже компилируя. FWIW Java-эквиваленты вашего пересмотренного кода, с одним добавлением явного построения BCECPublicKey из параметров, потому что JCE Signature принимает только тип Key, а не тип Parameters, работает для меня с тестовой парой ключей и данные. Вы можете попробовать выполнить аналогичное упражнение - создать пару ключей и подпись (для известных данных) в программном обеспечении и подтвердить, работает ли ваш код для этого случая, а затем попытаться изолировать различия в случае с аппаратной подписью. Хотя PKCS11 и другие аппаратные устройства часто разрабатываются для предотвращения экспорта сгенерированных ключами устройств в программное обеспечение, где они, вероятно, подвергаются большему риску компрометации, они не всегда настолько строги при импорте - вы можете использовать свое программное обеспечение. сгенерированный ключ в аппаратном обеспечении для сравнения.

В дополнение к общим причинам, по которым любая подпись не должна проверять (неправильные данные, неправильный хеш-код, который вы явно используете по умолчанию, неправильный ключ), существует и другая возможность , возможно - формат подписи. Существует два обычно используемых формата (или кодировки) для сигнатур ECDSA (и DSA): либо ПОСЛЕДОВАТЕЛЬНОСТЬ ИНТЕГРОВ ASN.1 в DER, либо просто два целых числа в фиксированном двоичном формате, объединенные без каких-либо метаданных. «Стандартная» Java (точнее, Java с поставщиками Sun / Oracle) использует только формат ASN.1; Java с Bouncy по умолчанию - ASN.1, но поддерживает фиксированный формат для ECDSA, если вы измените имя алгоритма на [hash]WITH{PLAIN,CVC}-ECDSA, поэтому я ожидаю, что Bouncy в dotNET (при условии, что ваш код использует его, хотя и не указано явно), может делать то же самое , Я понимаю (но не имею личного опыта) PKCS11 использует фиксированный формат. Если я передаю Java Bouncy в неправильном формате, он выдает исключение, а не возвращает verify = false, но я не знаю, может ли dotNET отличаться здесь. Посмотрите на значение вашей подписи подробно, чтобы проверить, какой это формат.

...