Skip to content

Commit

Permalink
feat: v0.2.6 | Add recoveryNested function for @doegox method
Browse files Browse the repository at this point in the history
  • Loading branch information
li0ard committed Mar 5, 2025
1 parent b9dc9bd commit e11497c
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 13 deletions.
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@li0ard/crapto1-ts",
"version": "0.2.6",
"version": "0.2.7",
"exports": "./src/index.ts",
"publish": {
"include": [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@li0ard/crapto1_ts",
"version": "0.2.6",
"version": "0.2.7",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
Expand Down
47 changes: 39 additions & 8 deletions src/crapto1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ export const lfsr_recovery64 = (ks2: number, ks3: number): Crypto1State[] => {
* Recovery by two sets of 32 bit keystream authentication
* @param uid UID
* @param chal Tag challenge #1 (aka `nt`)
* @param rchal Reader challenge #1 (aka `nr_0`)
* @param rresp Reader response #1 (aka `ar_0`)
* @param rchal Reader challenge #1 (aka `{nr_0}`)
* @param rresp Reader response #1 (aka `{ar_0}`)
* @param chal2 Tag challenge #2 (aka `nt1`)
* @param rchal2 Reader challenge #2 (aka `nr_1`)
* @param rresp2 Reader response #2 (aka `ar_1`)
* @param rchal2 Reader challenge #2 (aka `{nr_1}`)
* @param rresp2 Reader response #2 (aka `{ar_1}`)
* @returns {bigint}
*/
export const recovery32 = (uid: number, chal: number, rchal: number, rresp: number, chal2: number, rchal2: number, rresp2: number): bigint => {
Expand All @@ -277,10 +277,10 @@ export const recovery32 = (uid: number, chal: number, rchal: number, rresp: numb
/**
* Recovery by one set of full 64 bit keystream authentication
* @param uid UID
* @param chal Tag challenge
* @param rchal Reader challenge
* @param rresp Reader response
* @param tresp Tag response
* @param chal Tag challenge (aka `nt`)
* @param rchal Reader challenge (aka `{nr}`)
* @param rresp Reader response (aka `{ar}`)
* @param tresp Tag response (aka `{at}`)
* @returns {bigint}
*/
export const recovery64 = (uid: number, chal: number, rchal: number, rresp: number, tresp: number): bigint => {
Expand All @@ -293,4 +293,35 @@ export const recovery64 = (uid: number, chal: number, rchal: number, rresp: numb
lfsr_rollback_word(s, uid^chal)

return s.lfsr
}

/**
* Recovery by partial nested authentication
*
* @author doegox
* @param uid UID
* @param chal Tag challenge (aka `nt`)
* @param enc_chal Encrypted tag challenge (aka `{nt}`)
* @param rchal Reader challenge (aka `{nr}`)
* @param rresp Reader response (aka `{ar}`)
* @returns {bigint}
*/
export const recoveryNested = (uid: number, chal: number, enc_chal: number, rchal: number, rresp: number): bigint => {
let ar = prng_successor(chal, 64);
let ks0 = enc_chal ^ chal;
let ks2 = rresp ^ ar;

let s = lfsr_recovery32(ks0, uid ^ chal);

for (let t = 0; (s[t].odd !== 0) || (s[t].even !== 0); t++) {
crypto1_word(s[t], rchal, true);
if(ks2 == crypto1_word(s[t], 0)) {
lfsr_rollback_word(s[t], 0);
lfsr_rollback_word(s[t], rchal, true);
lfsr_rollback_word(s[t], uid ^ chal);
return s[t].lfsr
}
}

return -1n;
}
4 changes: 1 addition & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ export const bebit = (num: number, index: number): number => {
}

/**
* Filter function of Crypto1.
*
* Compute one bit of keystream from LFSR bits
* Filter function of Crypto1. Compute one bit of keystream from LFSR bits
* @param x LFSR bits
* @returns {number}
*/
Expand Down
11 changes: 11 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect, test } from "bun:test"
import { Crypto1State, encrypt, lfsr_rollback_byte, recovery32, recovery64 } from "../src/"
import { filter } from "../src/utils"
import { recoveryNested } from "../src/crapto1"

test("Recovery by 2 auths", () => {
// Real card
Expand Down Expand Up @@ -46,6 +47,16 @@ test("Recovery by 1 auth", () => {
)).toBe(0x62bea192fa37n)
})

test("Recovery by nested auth", () => {
expect(recoveryNested(
0x5c467f63,
0x4bbf8a12,
0xabb30bd1,
0x46033966,
0xadc18162
)).toBe(0x059e2905bfccn)
})

test("State", () => {
let testData = [
[0xd73A52b491AAn, 0x009E831F, 0x00F236A0],
Expand Down

0 comments on commit e11497c

Please sign in to comment.