Экспорт открытого ключа в base64 в Ruby

У меня есть открытый ключ в формате PEM, который был сгенерирован с помощью:

ecdsa_public_key = OpenSSL::PKey::EC.new ecdsa_private_key
ecdsa_public_key.private_key = nil
ecdsa_public_key.to_pem

Мне нужно прочитать строку PEM и получить строку URL-адреса в кодировке base64. Как я могу сделать это в Руби?

ecdsa_public_key = OpenSSL::PKey.read pem_string
ecdsa_public_key.to_base64 # pseudo code...

Кстати, я должен сделать это для протокола WebPush, в котором говорится:

вы должны добавить свой открытый ключ VAPID в заголовок Crypto-Key в виде закодированной строки URL-адреса base64 с добавлением p256ecdsa= к ней.


person collimarco    schedule 06.02.2017    source источник


Ответы (3)


Строка PEM на самом деле закодирована по основанию 64 (по крайней мере, частично), но я не думаю, что это то, что вам нужно здесь, она включает в себя другие детали, и я думаю, что вам нужны «сырые» данные открытого ключа.

Вот один из способов привести ключ к нужному формату. Это немного затянуто, но я не думаю, что привязки Ruby к OpenSSL предоставляют более прямой метод (сначала вам нужно require "base64"):

# Assuming the key is in ecdsa_public_key
Base64.urlsafe_encode64(ecdsa_public_key.public_key.to_bn.to_s(2), padding: false)

Это вызывает public_key для получения базового OpenSSL::PKey::EC::Point, затем преобразует его в OpenSSL::BN в правильном формате и преобразует его в двоичную строку. Наконец, эта строка закодирована в base64.

person matt    schedule 06.02.2017
comment
Спасибо!! Я постараюсь использовать его в ближайшие дни и посмотреть, работает ли он. Я использую Ruby 2.2.2: он не поддерживает padding: false. То же самое, если я вызову base64str.chomp('=').chomp('='), чтобы удалить все = в конце? - person collimarco; 07.02.2017
comment
@collimarco Или вы можете использовать str.delete("="), что и 2.4.0 делает. Я основывал свой код на примере из developers.google. .com/web/updates/2016/07/web-push-interop-wins, который не включает файл =. Может сработать, если вы их оставите, но может быть безопаснее их раздеть. - person matt; 07.02.2017
comment
Я даже не могу попробовать, потому что у меня есть другая проблема (которая может быть строго связана): stackoverflow.com/questions/42079185/ - person collimarco; 07.02.2017
comment
Спасибо! Я принял ответ, потому что попробовал, и он работает с Chrome! Кстати, у меня все еще есть другие проблемы с Firefox и открытым ключом... - person collimarco; 07.02.2017

Извините, что это немного поздно.

Я не очень хорошо знаком с Ruby, поэтому не могу предложить примеры кода, что делать, но могу попытаться описать процесс VAPID. (Кроме того, мои извинения, если я буду вдаваться в ненужные подробности, так как я полагаю, что другие могут наткнуться на это.)

Короче говоря, VAPID — это веб-токен Javascript (JWT). Вы создаете пару ключей ECDSA, используя свой любимый метод генерации ECDSA специально для VAPID.

e.g.

openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem
openssl ec -in vapid_private.pem -pubout -out vapid_public.pem

«PEM» — это форматированный файл, который включает стандартную строку заголовка, строку нижнего колонтитула и набор длинных строк дерьма. (Не уверен, что это технический термин для них, но да, я собираюсь пойти с этим.) Эти длинные строки дерьма представляют собой Base64-представления ключевых данных, сохраненных в определенных форматах.

Честно говоря, я НАСТОЯТЕЛЬНО рекомендую использовать библиотеку, где и когда это возможно. На jwt.io есть несколько библиотек Ruby, которые вы можете использовать, а также библиотеки для других языков. Что касается заголовка «Крипто-Ключ:», есть немного хороших новостей/других новостей.

  1. Вы можете просто взять длинные строки дерьма из вашего файла vapid-public.pem, сложить их вместе и указать как ключ 'p256ecdsa='.
  2. Протокол VAPID скоро изменится https://tools.ietf.org/html/draft-ietf-webpush-vapid-02

Это изменение эффективно избавляет от компонента Crypto-Key p256ecdsa. Вместо этого ключ авторизации становится:

Авторизация: vapid t=JWT, содержащий информацию VAPID,k=Открытый ключ VAPID

e.g.

vapid t=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYWlsdG86d2VicHVzaF9vcHNAY2F0ZmFjdHMuZXhhbXBsZS5jb20iLCJleHAiOjE0ODc0NDM3MTR9.mlLOWYMt-6aM3NB6b6_Msf8LqRKCuHd1Vfdp_fuJ3eqsQoID8lit305hIfNubTbvfACucuCygF3qB4scDbuHvg,k=EJwJZq_GN8jJbo1GGpyU70hmP2hbWAUpQFKDByKB81yldJ9GTklBM5xqEwuPM7VuQcyiLDhvovthPIXx-gsQRQ

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

person JR Conlin    schedule 17.02.2017

Вы могли бы попробовать

  require 'base64'
  Base64.encode64(ecdsa_public_key)

конвертировать в base64

person kitz    schedule 06.02.2017
comment
Он возвращает TypeError: no implicit conversion of OpenSSL::PKey::EC into String - person collimarco; 06.02.2017
comment
Если вы вызываете .to_s явно, вы получаете #<OpenSSL::PKey::EC:0x007fb731050970> - person collimarco; 06.02.2017
comment
Ваш объект должен иметь метод to_text [ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/PKey/. Итак, вы можете сделать Base64.encode64(ecdsa_public_key.to_text) - person kitz; 06.02.2017
comment
.to_text возвращает другую информацию, которая, строго говоря, не является ключом: "Private-Key: (256 bit)\npub: \n ..." - person collimarco; 06.02.2017