Ответ 1
Является ли калькулятор хеш файлов SHA256 неправильным инструментом для этого?
Он не работает, потому что вам нужно использовать двоичные данные для одного из шагов, и почти все веб-инструменты ожидают какой-то текст в качестве ввода и генерируют текст в качестве вывода. Онлайновые инструменты не подходят для этого. Я напишу инструмент, чтобы вы могли видеть, как это делается.
Как мне получить из токена доступа к значению претензии base64, закодированному at_hash, которое находится в токене id?
Это моя первая итерация программы на С# 2, поэтому, если это уродливо, потому что я никогда раньше не использовал ее. Объяснение после этого объяснит, как вычислить токен at_hash, включая то, зачем нам нужен decode_base64
.
using System;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text;
namespace AtHash
{
class AtHash
{
private const String access_token = "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg";
private const String id1 = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ";
private const String id2 = "eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9";
private byte[] decode_base64(String str) {
List<byte> l = new List<Byte>(Encoding.Default.GetBytes(str));
while (l.Count % 4 != 0 ){
l.Add(Convert.ToByte('='));
}
return Convert.FromBase64String(Encoding.Default.GetString(l.ToArray()));
}
public String sha256_at_hash(String access_token) {
SHA256Managed hashstring = new SHA256Managed();
byte[] bytes = Encoding.Default.GetBytes(access_token);
byte[] hash = hashstring.ComputeHash(bytes);
Byte[] sixteen_bytes = new Byte[16];
Array.Copy(hash, sixteen_bytes, 16);
return Convert.ToBase64String(sixteen_bytes).Trim('=');
}
public static void Main (string[] args) {
AtHash ah = new AtHash();
byte[] id1_str = ah.decode_base64 (id1);
byte[] id2_str = ah.decode_base64 (id2);
Console.WriteLine(Encoding.Default.GetString(id1_str));
Console.WriteLine(Encoding.Default.GetString(id2_str));
Console.WriteLine ("\n\tat_hash value == " + ah.sha256_at_hash(access_token));
}
}
}
Вывод этой программы (форматирование шахты)
{
"alg":"RS256",
"kid":"e11d57d1ff4804b31c051b71f6d5e5a1fd297cf8"
}
{
"exp" : 1432145822,
"iat" : 1432142222,
"azp" : "407408718192.apps.googleusercontent.com",
"aud" : "407408718192.apps.googleusercontent.com",
"email_verified" : true,
"iss" : "accounts.google.com",
"at_hash" : "lOtI0BRou0Z4LPtQuE8cCw",
"sub" : "110169484474386276334",
"email" : "[email protected]"
}
at_hash value == lOtI0BRou0Z4LPtQuE8cCw
Вот как проверить значение at_hash
. Вы можете пропустить часть google, если хотите использовать данные, которые я использовал, но если вы хотите протестировать их на новые данные, вы можете получить их в Google...
Получить токен доступа из Googles Игровая площадка O2Auth
Перейдите сюда
https://developers.google.com/oauthplayground/
Не выбирайте ничего, в нижней части страницы есть поле ввода. Введите openid
и нажмите Authorize APIs
, щелкните идентификатор, который хотите использовать, и выберите allow
. Выберите Exchange authorization code for tokens
. В случае успеха вы получите что-то похожее на следующее.
{
"access_token": "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg",
"token_type": "Bearer", "expires_in": 3600,
"refresh_token": "1/r5RRN6oRChjLtY5Y_T3lrqOy7n7QZJDQUVm8ZI1xGdoMEudVrK5jSpoR30zcRFq6",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9.jtnP4Ffw2bPjfxRAEvHI8j88YBI4OJrw2BU7AQUCP2AUOKRC5pxwVn3vRomGTKiuMbnHqMyMiVSQZWTjAgjQrmaANxTEA68UMKh3dtu63hh4LHkGJly2hFcIKwbHxMWPDRO9nv8LxAUeCF5ccMgFNXhu-i-CeVtrMOsjCq6j5Qc"
}
id_token состоит из трех частей, разделенных с использованием периода .
. Первые две части кодируются base64. Я игнорирую третью часть id_token. Нам нужно декодировать base64. Заметьте, я использую Perl, чтобы избежать необходимости использовать базовые строки, то есть Perl обрабатывает его для нас.
Первая часть, которую вы уже знаете, дает нам алгоритм, который нам нужно использовать.
perl -MMIME::Base64 -e 'print decode_base64("eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxMWQ1N2QxZmY0ODA0YjMxYzA1MWI3MWY2ZDVlNWExZmQyOTdjZjgifQ")'
{
"alg":"RS256",
"kid":"e11d57d1ff4804b31c051b71f6d5e5a1fd297cf8"
}
Вторая часть дает значение at_hash
.
perl -MMIME::Base64 -e 'print decode_base64("eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEwMTY5NDg0NDc0Mzg2Mjc2MzM0IiwiYXpwIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJiaWxsZDE2MDBAZ21haWwuY29tIiwiYXRfaGFzaCI6ImxPdEkwQlJvdTBaNExQdFF1RThjQ3ciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiNDA3NDA4NzE4MTkyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDMyMTQyMjIyLCJleHAiOjE0MzIxNDU4MjJ9")'
{
"iss":"accounts.google.com",
........
"at_hash":"lOtI0BRou0Z4LPtQuE8cCw",
........
"exp":1432145822
}
Теперь мы знаем, что такое значение at_hash
, мы можем использовать access_token
чтобы убедиться, что они одинаковые... Следующая программа Perl делает это.
#!/usr/bin/env perl
use strict;
use warnings;
use MIME::Base64;
use Digest::SHA qw(sha256);
my $data = "ya29.eQGmYe6H3fP_d65AY0pOMCFikA0f4hzVZGmTPPyv7k_l6HzlEIpFXnXGZjcMhkyyuqSMtN_RTGJ-xg";
my $digest = sha256($data);
my $first_16_bytes = substr($digest,0,16);
print encode_base64($first_16_bytes);
Эта программа может выполняться следующим образом
perl sha256.pl
lOtI0BRou0Z4LPtQuE8cCw==
Обратите внимание, что мы получили at_hash
, но почему они не совпадают..., они на самом деле одинаковы, и только один из них пропускает прокладку. Знаки =
добавляются до тех пор, пока не будет выполнено следующее.
(strlen($base64_string) % 4 == 0)
В нашем случае
strlen("lOtI0BRou0Z4LPtQuE8cCw") == 22
поэтому мы получили два ==
, добавленных к результату:). Причина, по которой они не в токене, состоит в том, что люди, написавшие спецификацию, не считают передачу лишних байтов по сети, это хорошая идея, если их можно добавить на другом конце.