Страницы

Поиск по вопросам

воскресенье, 7 июля 2019 г.

HEX ключ в .pem файл

У меня есть закрытый и открытые тестовые ключи в виде массивов байт(ну или HEX строки, без разницы). Хочу на тестовых ключах проверить правильность работы моего алгоритма. Все данные для теста тоже есть. Т.к. боевой ключ будет в виде файла .pem, то и алгоритм сделал под этот же тип файлов. Менять алгоритм под байты не хочу, т.к. опасаюсь что в момент конвертации что-нибудь пойдёт не так, поэтому хочу просто этот массив сохранить в файл .pem. Но вот как конвертировать, не понимаю. Понял что нужно HEX строку конвертировать в ASN.1, а уже потом в кодировку base64 и сохранить в файл.
Нашёл команду для openssl
echo "ASN.1" | xxd -r -p - | openssl ec -inform der -pubin -pubout -out key.pem
но она для ASN.1 строк, а как быть с HEX?
Использую шифрование ECDSA с кривой brainpoolP160r1

Как у меня даны тестовые ключи:
priv: 00:56:dc:b1:01:e2:ff:cd:95: 62:12:a1:01:21:05:01:1b:2f: 65:14:09 pub: 04:b1:dc:1b:2f:65:14:cd:95:55:12:02:01: 21:05:01:1b:2f:65:14:09:00:56:65:14:01: e2:c3:62:95:62:12:a1:08:21:05:01:1b:2f: 01:e2 ASN OID: brainpoolP160r1
Данные, которые буду шифровать представляют из себя массив байт размером 32 байта. В результате шифрования должна получиться подпись размером 48 байт.
Ключи выше, это выдуманные данные, реальные тестовые не могу предоставить.
Алгоритм, который у меня реализован вот:
var curve = new FpCurve( new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16), new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), BigInteger.One);
var g = curve.CreatePoint( new BigInteger("BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", 16), new BigInteger("1667CB477A1A8EC338F94741669C976316DA6321", 16));
var random = new SecureRandom();
StreamReader sr = new StreamReader("key.pem"); AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair) new PemReader(sr).ReadObject();
ISigner signer = SignerUtilities.GetSigner("SHA1withECDSA"); signer.Init(true, new ParametersWithRandom(keyPair.Public, random)); signer.BlockUpdate(message, 0, message.Length); byte[] signature = signer.GenerateSignature();


Ответ

.pem в конечном счёте содержит внутри ASN.1-закодированные данные, будь это приватный ключ или CSR. Формат ASN.1 довольно-таки замороченный. Если говорить об аналогиях, то это такой JSON, только из 1984 года.
Примерный вид. Как видите, в этом формате довольно-таки много движущихся частей.
Проблема здесь в том, что никакой штатной утилиты для конверсии ключа из человеко-читабельного вида в формат ASN.1 не существует, в том числе потому что это обычно никому не нужно. Потому одним вариантом было бы попросить у заказчика исходные ключи в виде .pem, если это вообще сколько-нибудь важно.
Если у вас есть только ключи, но нет никаких данных, которые были бы ими подписаны или зашифрованы, то вы с тем же успехом можете сделать новые ключи уже в .pem формате. Если у вас есть что-то, что нужно расшифровывать, или какая-то подпись для проверки, то либо просите у заказчика файлы ключей в .pem, либо разбирайтесь API для чтения и записи ASN.1 данных. Впрочем, можно не разбираться в API, а получить новый ключ, преобразовать его в бинарный вид и заменить прям в нём ключ на ваш, затем провести обратную процедуру.
Получить новую тестовую пару ключей для brainpoolP160r1 можно такими командами:
openssl ecparam -name brainpoolP160r1 -genkey -noout -out privkey.pem openssl ec -in privkey.pem -pubout -out pubkey.pem
Проверить результат можно так:
$ openssl ec -text -noout -in privkey.pem read EC key Private-Key: (160 bit) priv: ab:e0:fe:35:97:ac:b2:2a:eb:99:76:e7:1d:b9:7e: a7:d8:9e:98:62 pub: 04:14:40:2b:ec:80:c9:be:e0:b0:22:51:ea:83:c8: f8:4e:cc:a0:a9:01:7b:e8:54:c6:26:7d:61:07:c3: bf:76:d7:e7:2d:92:0f:90:8c:03:f1 ASN1 OID: brainpoolP160r1
Примерный вид ASN.1 можно посмотреть так:
$ openssl asn1parse -inform pem -i -out privkey.bin -in privkey.pem 0:d=0 hl=2 l= 84 cons: SEQUENCE 2:d=1 hl=2 l= 1 prim: INTEGER :01 5:d=1 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:ABE0FE3597ACB22AEB9976E71DB97EA7D89E9862 27:d=1 hl=2 l= 11 cons: cont [ 0 ] 29:d=2 hl=2 l= 9 prim: OBJECT :brainpoolP160r1 40:d=1 hl=2 l= 44 cons: cont [ 1 ] 42:d=2 hl=2 l= 42 prim: BIT STRING
Эта же команда сохранит ключ в бинарном виде в privkey.bin. Если посмотреть на него внимательно, то:
$ od -A n --format x1 privkey.bin 30 54 02 01 01 04 14 ab e0 fe 35 97 ac b2 2a eb ^^^^^^^^^^^^^^ начало ключа ABE0FE3597... 99 76 e7 1d b9 7e a7 d8 9e 98 62 a0 0b 06 09 2b 24 03 03 02 08 01 01 01 a1 2c 03 2a 00 04 14 40 2b ec 80 c9 be e0 b0 22 51 ea 83 c8 f8 4e cc a0 a9 01 7b e8 54 c6 26 7d 61 07 c3 bf 76 d7 e7 2d 92 0f 90 8c 03 f1
Можно увидеть где начинается и где заканчивается этот конкретный ключ. Дальше используя любой подходящий HEX-редактор заменяем ключ на свой, конвертируем обратно в .pem из DER, получаем публичный ключ той же командой что выше, готово.
HEX-редактор можно изобрести на коленке:
hexdump -ve '1/1 "%.2X"' privkey.bin | sed s/ABE0FE3597ACB22AEB9976E71DB97EA7D89E9862/ваш ключ/ | xxd -r -p > newprivkey.bin
Конвертация приватного ключа из DER в .pem делается командой:
openssl ec -inform DER -in newprivkey.bin -out newprivkey.pem
Аналогично для вычисления публичной части:
openssl ec -inform DER -in newprivkey.bin -pubout -out newpubkey.pem

Комментариев нет:

Отправить комментарий