- Külföldi prepaid SIM-ek itthon
- Poco X6 Pro - ötös alá
- Új design és okosabb AI: megjött a Galaxy S25 készülékcsalád
- Milyen okostelefont vegyek?
- Samsung Galaxy A53 5G - kevesebbet többért
- Nothing: március 4
- Január 30-tól Magyarországon is kapható a Vivo X200 Pro
- Az App Store-ban már kiütötte a ChatGPT-t a DeepSeek, tévúton az AI-szektor?
- Fotók, videók mobillal
- Milyen hagyományos (nem okos-) telefont vegyek?
Új hozzászólás Aktív témák
-
-
"Elvileg javascript-ben is meg lehetne csinálni egy helyben futtatható verziót, ahhoz a böngészőn kívül nem kellene más."
Nagyjából bármelyik nyelven meg lehet csinálni, a totp.app pedig éppen a JS implementációra egy kiváló példa (az egész üzleti logika JS-ben van megírva, a HTML alap csak a betöltéshez, a CSS pedig a látványhoz kell). Attól azonban nem feltétlenül csökken a faktor szám, ha nem ugyanabban a böngészőben fut a generátor és az Ügyfélkapu+.
#34 ekkold
Olvass tovább, nevemfel kolléga pont a helyi gépen való PHP futtatásra írt egy példát. Mellesleg én is így futtattam fejlesztés közben: parancssorból, nem böngészőből.#35 nevemfel
Nem kell hozzá semmilyen módosítás, akár saját, akár linkelt base32 dekódert használsz. Én egészen konkrétan ezt a programot futtattam parancssorból. Igaz, nem Windows alól portable PHP-val, hanem Linux alól telepítettel.[ Szerkesztve ]
-
válasz Geri Bátyó #31 üzenetére
A "nulla tudás" csak Rajtad múlik, a net pedig tele van tutorialokkal. Viszont a cucc működhet saját gépről is, helyben, de akkor csak abban az esetben tudod távolról elérni, ha neten nyitsz neki egy portot az otthoni routereden és foglalsz hozzá egy az otthoni IP címedet követő dinamikus domaint, hogy "hazatalálj".
-
válasz Geri Bátyó #28 üzenetére
Fontos hangsúlyozni, hogy a program csak a működési elvre fókuszál és nulla védelemmel van ellátva (hozzáférési jelszó, kulcs elszeparált/titkosított tárolása stb.). De ha nagyon le akarom egyszerűsíteni a dolgot, akkor az alábbiakkal már összehozhatod a saját TOTP kliensedet:
- egy kellően biztonságos webtárhely, ami PHP futtatásra alkalmas,
- egy domain, amin keresztül eléred a fenti webtárhelyen futó programot.Bárhol (bármilyen eszközön) is hívod meg a szolgáltatást, az kiköpi Neked az éppen aktuális 6 számjegyű kódodat. Ennyi.
-
És íme egy saját "minimál" base32 dekóder, levezetés gyanánt:
function base32_decode(string $text)
{
$abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
$i = 0;
$l = strlen($text = trim(strtoupper($text)));
$result = '';
$fivebyte = 0;
while ($i < $l) {
$f = $i % 8;
if ($text[$i] == '=') break;
$p = strpos($abc, $text[$i]);
if ($p === false) throw new \Exception('Illegal base32 character: ' . $text[$i]);
$fivebyte |= ($p << (35 - $f * 5));
if ($f == 7) {
$result .= str_pad(dechex($fivebyte), 10, '0', STR_PAD_LEFT);
$fivebyte = 0;
}
$i++;
}
if ($text[$i] == '=') {
$result .= substr(str_pad(dechex($fivebyte), 10, '0', STR_PAD_LEFT), 0, $i % 8);
}
return hex2bin($result);
}Forrás RFC 4648. Most pedig szunya!
-
No, megpróbálom röviden és érthetően leírni a program működését. Hozzáértők, nyugodtan szóljatok hozzá!
<?php
// Betöltjük a Base2n nevű osztály forráskódját, ezzel elérhetővé válik a base32 kóder/dekóder szolgáltatás. Részletek lejjebb.
require_once("Base2n.php");
// Beállítjuk az időzónánkat. Erre azért van szükség, mert a TOTP szabvány UTC világórához van kötve, a mi rendszeróránk viszont CET időzóna szerint ketyeg. Ha tehát a mi óránk ma, január 27-én 20:02-t mutat, az UTC szerint 19:02. Ezt az Ügyfélkapu+ is tudja, hiszen ő is ugyanezt az algoritmust használja, nekünk pedig lehetőség szerint másodpercre pontosan együtt kell vele ketyegnünk.
date_default_timezone_set('Europe/Budapest');
// Létrehozzunk azt az objektumot, ami a base32 dekódolást fogja elvégezni. Azért így, mert a Base2n osztály egy általános felhasználású osztály, többféle kódolást is képes alkalmazni, a base32 pedig az alábbi ábécével és egyéb paraméterekkel inicializálható. De ez egy példa, ekkold kolléga már bemutatta a saját megoldását, az is tök jó.
$base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', false, true, true);
// Definiálunk egy speciális, ún. "hash" függvényt, ami a paraméterként átadott kulccsal (1. paraméter) és pad bájt (2. paraméter) segítségével egy fix hosszúságú, de a tartalom függvényében jelentősen változékony tartalommal bíró bináris bájtsorrá kódolja a 3. "text" paramétert. Ez a "text" persze lehet bármilyen bináris bájtsor is, a tartalma lényegtelen.
function h(string $key, int $pad, string $text)
{
// A kulcsot 64 bájtra egészítjük ki jobbról feltöltve nullás bájtokkal.
$key = str_pad($key, 64, chr(0x00), STR_PAD_RIGHT);
// A 64 bájtra hízlalt kulcs minden bájtján XOR bitműveletet (kizáró VAGY) hajtunk végre a pad értékével, ami szintén egy bájt. Ezzel a kulcs bitjeinek eloszlását szétszórjuk a spektrumon, egyszerűbben mondva, zajosabbá tesszük.
for ($i = strlen($key) - 1; $i >= 0; $i--) {
$key[$i] = chr(ord($key[$i]) ^ $pad);
}
// A 64 bájtos, zajos kulcshoz jobbról hozzáfűzzük a titkosítandó "szövegünk" bájtjait (ami majd látjuk, hogy valójában nem is szöveg) és alávetjük az SHA-1 hash-elésnek. Az eredmény egy 20 bájt (azaz 160 bit) hosszú bináris bájtsor. (Ha a 3. paraméter false lenne true helyett, akkor az eredmény ugyanennek a 20 bájtnak a hexadecimális megfelelője volna, azaz egy 40 karakteres string.)
return hash('sha1', $key . $text, true);
}
// Lekérdezzük a rendszeridőt, ami UTC időzónában értelmezett, 1970.01.01 00:00:00 óta eltelt másodpercek száma lesz.
$t = time();
// Ezt a ~1,7 milliárdos számot elosztjuk 30-cal és csak az egész részt tartjuk meg. Ezzel egy ~57 milliós értéket fogunk kapni, ami 30 másodpercenként növeli az értékét eggyel.
$t30 = (int)floor($t / 30);
// Fogjuk ezt a 30 másodperceként lépkedő számlálót és átalakítjuk egy 8 bájtos (64 bites) big-endian egésszé. Ezt úgy csináljuk, hogy először a számot átalakítjuk hexadecimálissá, balról feltöltjük '0'-ás karakterekkel, amíg 16 karakter hosszú nem lesz, majd az egészet visszaalakítjuk egy bináris bájtsorrá, ami pont 8 bájt hosszú lesz és történetesen string típusú. De ezt elolvasni nem fogjuk tudni, bár nem is célunk.
$c = hex2bin(str_pad(dechex($t30), 16, '0', STR_PAD_LEFT));
// Közben előkapjuk az Ügyfélkapu+-tól kapott 16 karakteres kulcsunkat, ami valójában base32 eljárással van elkódolva. Az eredmény egy ~10 elemű bájtsor lesz.
$key = $base32->decode('IDEJONAZUGYFELKAPUTOLKAPOTT16JEGYUKULCSOD');
// Fogjuk a fent definiált hash függvényünket és meghívjuk a ~10 bájtos (immáron dekódolt) kulcsunkkal, egy 0x36 (54) értékű pad bájttal és a 8 bájton tárolt számlálónkkal. Ezután újra meghívjuk a ~10 bájtos kulcsunkkal, egy 0x5c (92) értékű pad bájttal és az előbbi hívásunk eredményeként kiköpött hash eredményünkkel. Az eredmény egy 20 bájtos (160 bites) bájtsor lesz.
$h = h($key, 0x5c, h($key, 0x36, $c));
// Vesszük ennek az utolsó (huszadik, azaz mivel 0-kezdetű tömbindexelést használunk, 19. indexű) elemét, ami -- mivel stringben tároljuk az hash-elésünk eredményét -- egy karakter lesz. Ahhoz, hogy ebből egy számot kapjunk át kell kergetnünk az ord() függvényen. Végül pedig, egy AND bitművelettel elmaszkolva megtartjuk az utolsó 4 bitjét. Ennek köszönhetően az eredmény egy 0...15 közötti szám lesz, amit offszetként fogunk használni.
$o = ord($h[strlen($h) - 1]) & 0x0f;
// Vesszük a hash-elésünk eredményeként született bájtsort (ami string típusú) és rábökünk annak "offszetedik" elemére. Az ord()-dal egésszé konvertáljuk, AND bitművelettel elmaszkolva megtartjuk az utolsó 7 bitjét, majd balra el-shift-eljük 24 bittel.
$r = (ord($h[$o]) & 0x7f) << 24
// Fogjuk a hash bájtsorunk "offszet+1-edik" elemét, egésszé alakítjuk és eltoljuk balra 16 bittel.
| ord($h[$o + 1]) << 16
// Fogjuk a hash bájtsorunk "offszet+2-edik" elemét, egésszé alakítjuk és eltoljuk balra 8 bittel.
| ord($h[$o + 2]) << 8
// Fogjuk a hash bájtsorunk "offszet+3-adik" elemét, egésszé alakítjuk.
| ord($h[$o + 3]);
// Ezt a 4 bájtot OR bitműveletekkel összefésüljük, így kapunk egy 31 bites egész számot, ami a 0...2147483647 tartományban kaphat majd értéket.
// Fogjuk ezt a 31 bites egészt és vesszük az egymillióval való osztás maradék részét, ami így egy legfeljebb 6 számjegyű decimális szám lesz. Annak érdekében viszont, hogy ez a szám garantáltan 6 számjegyű legyen, szöveggé alakítjuk és balról feltöltjük '0'-ás karakterekkel. És ezzel meg is van a 6 számjegyű kódunk.
echo str_pad($r % 1000000, 6, '0', STR_PAD_LEFT) . "\n";
-
válasz Geri Bátyó #17 üzenetére
Ahhoz, hogy válaszoljak erre a kérdésre, tudnom kellene, miféle felhasználóval van dolgom.
Ha van affinitásod a PHP-hoz, akkor a kérdés nem kérdés: beüzemelsz egy gépet, amin fut a PHP, és már meg is van a saját TOTP generátorod. Az már csak hálózati konfiguráció kérdése, mivel honnan akarod vagy vagy hajlandó elérni. A bejegyzés azoknak szól elsősorban, akik kíváncsiak az utóbbi időben sokszor és sokak által tárgyalt TOTP algoritmus működésére, és/vagy szeretnének saját megoldást, ami senki mástól nem függ (sem a Google-tól, sem az MS-től, sem a TOTP.APP orosz fejlesztőjétől, de még csak a magyar államtól sem).
#18 Inhouse
Azért nem osztom a nézetedet, mert a hangsúly a saját, és mindenki mástól független megoldáson van. Az Általad leírt megoldás függ a base32 dekóder szolgáltatástól és a onecompiler.com-tól. Ráadásul a kulcsod online dekódolásával és a programod harmadik fél portálján keresztül történő futtatásával Te magad szolgáltatod ki a titkos(nak szánt) adataidat. Ne tedd! -
"A pontok szóközöket helyettesítenek, csak a fórummotor kiszedi őket..."
Nem szóközök, hanem nullás bájtok, amiknek nincs (olvasható) karakteres megfelelője. És nem a fórum motor, hanem a HTML "szedi ki őket", valójában pedig csak összevonja a white space-eket. A HTML alapú megjelenítés sok szempontból nem szerencsés ilyen esetben, de a hexadecimális formátum sokat tud ebben segíteni. Hasonló okból barátai a fejlesztőknek a hexa editorok.
-
"Ez a hex2bin() meg csak párat."
Ugye nem a képernyőről próbálod leolvasni hány bájtot gyárt a függvény? Mondom, bármit is kapsz ennek kimenetéül, azt ne próbáld szövegként elolvasni!
Egyébként rém egyszerű a működése, mert a függvény hexadecimális bemenetének és bináris kimenetének hossza (bájt- vagy ha úgy tetszik, karakterszáma) között egy 2-es osztó áll: beadsz neki n (páros) számú hexadecimális karaktert string formájában és kiad n/2 számú bájtot szintén string formájában. Amit csak akkor tudsz olvasni, ha mindegyik bájt értéke a 32...127 (hexadecimálisan 0x20...0x7f) tartományban van, ami jelen esetben nagy eséllyel nincs így.
-
válasz cinemazealot #8 üzenetére
"Mert ha jól sejtem, tegnap 18:23:30-kor futtattad."
Bocs, 18:23:30 és 18:23:59 között.
-
Még egyszer: a hex2bin() kimenete nem egy hétköznapi (olvasható) string, hanem egy (jelen pillanatban 8 karakter, azaz 8 bájt hosszú) 64 bites integer string-ként tárolva. Pusztán azért, mert így kényelmesebb vele dolgozni. Ne próbáld megfejteni "00|00|00|00|03|73|f2|a7" bájtsorozat (string) szöveges jelentését, mert nincs neki olyan. Ez nem más, mint az 57930407 értékű egész szám big-endian ábrázolása, ami a 1737912210/30 matematikai művelet eredményeként született. Mert ha jól sejtem, tegnap 18:23:30-kor futtattad.
Online szerintem ne akarj PHP-t futtatni, inkább telepíts fel egyet magadnak, futtasd a programot parancssorból és itt-ott állítsd meg, hogy "kiechózd" egyik-másik változót. Viszont kiechózni sem lehet mindent, pl. a bináris tartalom parancssorban is szarul mutatna. Ahhoz előbb érdemes beletenni a bináris tartalmat egy bin2hex()-be, csak hogy hexadecimálisan olvasható legyen.
Még egy gondolat a stringekhez: a PHP-ban minden bináris tartalom (pl. hang, kép, videó, Excel tábla, Word vagy PDF dokumentum) betölthető stringbe. Nyilvánvaló, hogy egy ilyet kiírni szövegként teljességgel értelmetlen volna, mert az csak egy bájtsor, aminek elemei bőven túlmutathatnak az ASCII kódtáblán.
Szerk.: Most melózom, de ha igény van rá, este leírom egy hsz-ben az egész program működését sorról-sorra.
[ Szerkesztve ]
-
Szia Inhouse!
A hex2bin() pontosan azt teszi, amit a neve sugall, illetve amit a manual ír róla: egy bináris stringet hoz létre. Ennek azonban nem feltétele, hogy a string ember által olvasható is legyen. Ha megfigyeled, az eredménye csupán egy 64 bites (8 bájtos) "big-endian" integer, aminek alapja a 30 másodpercenkénti számláló, kiegészítve balról nulla karakterekkel (!). Mivel az alapja integer, amúgy sem lenne string formában olvasható, de nem is ez a cél, hanem hogy bekerüljön a h() függvénybe, ahol a jobbról nulla bájtokkal (!) kiegészített és aztán jól "meg-scramble-zött" kulcshoz hozzáfűzve ráeresztjük az SHA1-et... aztán mégegyszer egy másik pad bájttal.
Olvasd el a linkelt szabványt... illetve az abban hivatkozott RFC 4226 és RFC 2104 szabványokat, utóbbiban lesz jobban kifejtve ez a fenti eljárás.
-
Szuper, örülök.
#2 ekkold
Olvastam a megoldásodról, irigykedtem is, hogy megelőztél. De azon túl, hogy egy bagatell problémán akadtam fenn, én kizárólag a TOTP magjára fókuszáltam. Aztán ha valaki olyan összkomfortos megoldást akar, mint a Tiéd, az legfeljebb körülbástyázza az áhított védelmi és kényelmi funkciókkal.#3 Doky586
Nem beszélve arról a pár ezer forintos kínai switch-ről, amit a minap tettem a hálózatra.
Új hozzászólás Aktív témák
Állásajánlatok
Cég: Marketing Budget
Város: Budapest