Поколение ecdsa 32-байтового закрытого ключа в Java / Scala - PullRequest
0 голосов
/ 12 сентября 2018

возможно ли сгенерировать 32-байтовый закрытый ключ ecdsa в Java с помощью KeyPairGenerator? Я имею в виду, что keys.getPublic.getEncoded.length вернет 32 Я пытался сгенерировать закрытый ключ, но размер 144 байта

//keys.getPrivate.getEncoded.length - 144 bytes
val ecSpec: ECNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1")
val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC")
val secRandom = new SecureRandom()
keyPairGenerator.initialize(ecSpec, secRandom)
val keys = keyPairGenerator.generateKeyPair

//keys.getPrivate.getEncoded.length - 67 bytes
val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("EC")
keyPairGenerator.initialize(256)
val keys = keyPairGenerator.generateKeyPair

1 Ответ

0 голосов
/ 12 сентября 2018

Значение, возвращаемое из Java PrivateKey.getEncoded(), является частной клавишей в кодировке , как следует из названия. В частности, , как указано в суперклассе Key, это кодировка ASN.1 (DER) PKCS # 8 = стандарт шифрования с открытым ключом # 8, Синтаксис информации личного ключа . PKCS # 8 обрабатывает приватные ключи для широкого спектра различных алгоритмов открытого ключа и содержит метаданные в дополнение к фактическому ключу, а именно «AlgorithmIdentifier», который идентифицирует алгоритм и любые параметры алгоритма; для алгоритма (ов) ECC (ECDSA, ECDH, ECMQV и другие совместно используют один ключевой формат) эти параметры указывают используемую группу эллиптических кривых, и хотя для этой спецификации существует несколько вариантов, на практике каждый, включая здесь Java, использует ' Параметр namedCurve ', который определяет группу кривых по идентификатору объекта ASN.1, также известному как Идентификатор объекта.

Затем структура PKCS # 8 содержит фактические данные закрытого ключа, «обернутые» в СТРОКУ ОКТЕТА, в формате, который изменяется в зависимости от алгоритма. Для ECC этот формат определен (AFAICT) в SEC1 с помощью SECG / Certicom и содержит фактическое значение закрытого ключа (число, выраженное как OCTET STRING) плюс , необязательно спецификация кривой и открытый ключ.

Ваш первый код использует BouncyCastle, и Bouncy генерирует кодировку с включенным значением, включая необязательную спецификацию кривой и открытый ключ, делая его длиннее.

Ваш второй код по умолчанию использует провайдера Oracle / Sun (SunEC), который генерирует кодировку без этих опций, но все еще включает в себя требуемый AlgorithmIdentifier, что делает его длиннее фактического значения privatekey. Он также использует другую кривую : при инициализации генератора SunEC с целым числом 256 выбирается secp256r1 (он же P-256, prime256v1), а не secp256k1. Если вы измените его на использование new ECGenParameterSpec("secp256k1") в качестве параметра, SunEC также сгенерирует secp256k1, но без параметров, предоставляя 64-байтовую кодировку.

В обоих случаях, если вам нужен только закрытый ключ номер , приведите к java.security.interfaces.ECPrivateKey и используйте getS(). Если вы хотите получить результат в байтовом / октетном массиве, как это принято, обратите внимание, BigInteger.toByteArray() возвращает результат переменной длины, и вам часто нужно оставить нулевое усечение или дополнить его.

И если вы действительно хотели публичный ключ, он имеет аналогичную схему, использующую кодировку 'X.509', которая содержит и AlgorithmIdentifier, и BIT STRING, заключающие фактическое значение publickey, и, следовательно, длиннее, чем необработанное значение publickey. Однако в этом случае interfaces.ECPublicKey и spec.ECPoint не создадут кодировку для вас; использование Bouncy-only типов может быть более удобным.

...