Как построить закрытый ключ из сгенерированной ранее пары закодированных ключей ECDSA?

Создав такой закрытый ключ:

    fun getKeyPair(): Pair<ByteArray, ByteArray> {
        Security.addProvider(provider)
        val generator = KeyPairGenerator.getInstance("ECDSA")
        val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
        generator.initialize(ecSpec)
        val keyPair = generator.generateKeyPair()
        val publicKey = keyPair.public as ECPublicKey
        val privateKey = keyPair.private
        return Pair(publicKey.q.getEncoded(true), privateKey.getEncoded())
    }

Открытый ключ можно снова восстановить следующим образом:

    Security.addProvider(...spongy castle provider)
    val ecSpecs = ECNamedCurveTable.getParameterSpec("secp256r1")
    val q = ecSpecs.curve.decodePoint(publicKeyEncoded)
    val pubSpec = ECPublicKeySpec(q, ecSpecs)
    val keyFactory = KeyFactory.getInstance("ECDSA")
    val generatedPublic = keyFactory.generatePublic(pubSpec)

Как можно вместе с этим восстановить закрытый ключ из байтов?

ОБНОВИТЬ:

Этот код хорошо работает в реальном приложении, но не работает при тестировании JUnit:

val keyFactory = KeyFactory.getInstance("ECDSA")
val privSpec = PKCS8EncodedKeySpec(privateEncoded)
val generatedPrivate = keyFactory.generatePrivate(privSpec)

В тесте JUnit я получаю эту ошибку:

java.security.spec.InvalidKeySpecException: encoded key spec not recognised

Мой закрытый ключ в виде закодированных байтов имеет размер 150 байтов.


person K.Os    schedule 13.12.2018    source источник
comment
Чтобы узнать формат закодированного ключа и, следовательно, подсказку для типа KeySpec, необходимого для его регенерации, изучите свойство .format ключа, например val privFormat = privateKey.format   -  person President James K. Polk    schedule 14.12.2018
comment
Убедитесь, что и ваше приложение, и Junit используют установленного вами провайдера. Security.addProvider (provider) устанавливает поставщика в конце, поэтому, если в системе есть другой поставщик, способный обрабатывать ключи EC, он будет использоваться, и вы можете получить неожиданные результаты. Вы можете использовать Security.insertProviderAt (sc, 1); или указать его при вызове KeyFactory.getInstance ("ECDSA", "SC")   -  person pedrofb    schedule 19.12.2018
comment
@pedrofb К сожалению, я, конечно, пробовал - не вышло   -  person K.Os    schedule 19.12.2018
comment
У меня такое чувство, что я уже упоминал об этом раньше, но среда тестирования Android Studio Junit находится на хосте, а не на Android. Поэтому поставщиком безопасности, используемым в модульных тестах, может потребоваться быть официальным поставщиком bouncycastle, а не spongycastle.   -  person President James K. Polk    schedule 19.12.2018
comment
publicKey.q.getEncoded(true), похоже, не компилируется в моей среде. Для ECPublicKey нет свойства q. Конечно, я действительно не знаю Kotlin, кроме слепых поисков в среде IDE.   -  person President James K. Polk    schedule 19.12.2018
comment
@JamesKPolk, вы можете увидеть, как это делается, здесь: stackoverflow.com/questions/53629537/. Я использую SpongyCastle (поскольку он предназначен только для разработки Android - с использованием Android Studio)   -  person K.Os    schedule 19.12.2018
comment
хорошо, но вы не обратили внимания на мой предыдущий комментарий. Ваша среда тестирования может использовать локальные модульные тесты, которые выполняются на хосте. host - это не android, это то, на чем работает Android Studio, например Windows / Linux / Mac OS X   -  person President James K. Polk    schedule 19.12.2018


Ответы (1)


Поскольку ключ закодирован с использованием стандартного Key.getEncoded(), должно работать следующее стандартное решение:

val keyFactory = KeyFactory.getInstance("EC")
val privSpec = PKCS8EncodedKeySpec(privateEncoded)
val generatedPrivate = keyFactory.generatePrivate(privSpec)

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

person Kiskae    schedule 13.12.2018
comment
К сожалению, когда я использовал это, а затем хочу протестировать это поколение в своем тесте JUnit, я получаю эту ошибку: java.security.spec.InvalidKeySpecException: спецификация закодированного ключа не распознана Я использую AndroidStudio - когда я запускаю этот код в реальном приложение это работает. Можешь мне помочь? - person K.Os; 19.12.2018
comment
Тот факт, что он работает на некоторых платформах, но не работает на других, указывает на то, что сам код в порядке. Вы зарегистрировали провайдер безопасности для последней части кода? - person Kiskae; 19.12.2018
comment
Не знаю, что вы конкретно имеете в виду, но я зарегистрировал поставщика безопасности, как в вопросе выше (см. Код) - person K.Os; 19.12.2018