chameleon-ultra.js - v0.3.29
    Preparing search index...

    Class Crypto1

    JavaScript implementation of the Crypto1 cipher.

    Index

    Constructors

    • Parameters

      • opts: { even?: number; odd?: number } = {}
        • Optionaleven?: number

          The even bits of lfsr.

        • Optionalodd?: number

          The odd bits of lfsr.

      Returns Crypto1

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      const state1 = new Crypto1()
      const state2 = new Crypto1({ even: 0, odd: 0 })

    Methods

    • Get the value of lfsr.

      Returns number

      lfsr.

      const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      const state1 = new Crypto1()
      console.log(state1.setLfsr(new Buffer('FFFFFFFFFFFF')).getLfsr().toString(16)) // 'FFFFFFFFFFFF'
    • Get the lfsr output bit and update lfsr by input bit.

      Parameters

      • input: number

        The input bit.

      • isEncrypted: number

        Indicates whether the input bit is encrypted or not.

      Returns number

      The lfsr output bit.

    • Get the lfsr output byte and update lfsr by input byte.

      Parameters

      • input: number

        The input byte.

      • isEncrypted: number

        Indicates whether the input byte is encrypted or not.

      Returns number

      The lfsr output byte.

    • Rollback the lfsr in order to get previous states

      Parameters

      • input: number

        The input bit.

      • isEncrypted: number

        Indicates whether the input bit is encrypted or not.

      Returns number

      The lfsr output bit.

    • Rollback the lfsr in order to get previous states

      Parameters

      • input: number

        The input byte.

      • isEncrypted: number

        Indicates whether the input byte is encrypted or not.

      Returns number

      The lfsr output byte.

    • Rollback the lfsr in order to get previous states

      Parameters

      • input: number

        The 32-bit input word.

      • isEncrypted: number

        Indicates whether the 32-bit input word is encrypted or not.

      Returns number

      The lfsr 32-bit output word.

    • Get the lfsr 32-bit output word and update lfsr by 32-bit input word.

      Parameters

      • input: number

        The 32-bit input word.

      • isEncrypted: number

        Indicates whether the 32-bit input word is encrypted or not.

      Returns number

      The lfsr 32-bit output word.

    • Reset the internal lfsr.

      Returns this

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      const state1 = new Crypto1({ even: 1, odd: 1 })
      state1.reset()
    • Set the internal lfsr with the key.

      Parameters

      • key: number

        The key to set the internal lfsr.

      Returns this

      const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      const state1 = new Crypto1()
      state1.setLfsr(new Buffer('FFFFFFFFFFFF'))
    • Recover the key from the tag with the darkside attack.

      Parameters

      • fnAcquire: (
            attempt: number,
        ) => Promise<
            {
                ar: Buffer;
                ks: Buffer;
                nr: Buffer;
                nt: Buffer;
                par: Buffer;
                uid: Buffer;
            },
        >

        An async function to acquire the darkside attack data.

      • fnCheckKey: (key: Buffer) => Promise<boolean>

        An async function to check the key.

      • attempts: number = 256

        The maximum number of attempts to try.

      Returns Promise<Buffer>

      The recovered key.

      // you can run in DevTools of https://taichunmin.idv.tw/chameleon-ultra.js/test.html
      await (async ultra => {
      const { Buffer, DarksideStatus, DeviceMode, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')
      await ultra.cmdChangeDeviceMode(DeviceMode.READER)
      const block = 0
      const keyType = Mf1KeyType.KEY_A
      const key = await Crypto1.darkside(
      async attempt => {
      const accquired = await ultra.cmdMf1AcquireDarkside(block, keyType, attempt === 0)
      console.log(_.mapValues(accquired, buf => Buffer.isBuffer(buf) ? buf.toString('hex') : buf))
      if (acquired.status === DarksideStatus.LUCKY_AUTH_OK) throw new Error('LUCKY_AUTH_OK')
      if (acquired.status !== DarksideStatus.OK) throw new Error('card is not vulnerable to Darkside attack')
      return accquired
      },
      async key => {
      return await ultra.cmdMf1CheckBlockKey({ block, keyType, key })
      },
      )
      console.log(`key founded: ${key.toString('hex')}`)
      })(vm.ultra)
    • Decrypt the data.

      Parameters

      • opts: {
            data: Buffer;
            key: Buffer;
            nr: string | number | Buffer;
            nt: string | number | Buffer;
            uid: string | number | Buffer;
        }
        • data: Buffer

          The encrypted data.

        • key: Buffer

          The 6-bytes key to decrypt the data.

        • nr: string | number | Buffer

          The calculated response of args.nt from reader in the authentication.

        • nt: string | number | Buffer

          The nonce from tag in the authentication.

        • uid: string | number | Buffer

          The 4-bytes uid in the authentication.

      Returns Buffer

      The decrypted data.

    • A method for Tag to validate Reader has the correct key.

      Parameters

      • opts: {
            ar: string | number | Buffer;
            key: Buffer;
            nr: string | number | Buffer;
            nt: string | number | Buffer;
            uid: string | number | Buffer;
        }
        • ar: string | number | Buffer

          The encrypted prng successor of opts.nt.

        • key: Buffer

          The 6-bytes key to be test.

        • nr: string | number | Buffer

          The encrypted nonce from reader.

        • nt: string | number | Buffer

          The nonce from tag.

        • uid: string | number | Buffer

          The 4-bytes uid of tag.

      Returns boolean

      const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.mfkey32IsReaderHasKey({
      ar: 'CF0A3C7E',
      key: 'A9AC67832330',
      nr: 'FEDAC6D2',
      nt: '2C198BE4',
      uid: '65535D33',
      }).toString('hex')) // true
    • Recover the key with the two authentication attempts from reader.

      Parameters

      • opts: {
            ar0: string | number | Buffer;
            ar1: string | number | Buffer;
            nr0: string | number | Buffer;
            nr1: string | number | Buffer;
            nt0: string | number | Buffer;
            nt1: string | number | Buffer;
            uid: string | number | Buffer;
        }
        • ar0: string | number | Buffer

          The random challenge from reader in the first authentication attempt.

        • ar1: string | number | Buffer

          The random challenge from reader in the second authentication attempt.

        • nr0: string | number | Buffer

          The calculated nonce response from reader in the first authentication attempt.

        • nr1: string | number | Buffer

          The calculated nonce response from reader in the second authentication attempt.

        • nt0: string | number | Buffer

          The nonce from tag in the first authentication attempt.

        • nt1: string | number | Buffer

          The nonce from tag in the second authentication attempt.

        • uid: string | number | Buffer

          The 4-bytes uid in the authentication attempt.

      Returns Buffer

      The recovered key.

      const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.mfkey32v2({
      uid: 0x65535D33,
      nt0: 0xCB7B9ED9,
      nr0: 0x5A8FFEC6,
      ar0: 0x5C7C6F89,
      nt1: 0x1E6D9228,
      nr1: 0x6FB8B4A8,
      ar1: 0xEF4039FB,
      }).toString('hex')) // A9AC67832330
      console.log(Crypto1.mfkey32v2({
      uid: Buffer.fromHex('65535D33'),
      nt0: Buffer.fromHex('CB7B9ED9'),
      nr0: Buffer.fromHex('5A8FFEC6'),
      ar0: Buffer.fromHex('5C7C6F89'),
      nt1: Buffer.fromHex('1E6D9228'),
      nr1: Buffer.fromHex('6FB8B4A8'),
      ar1: Buffer.fromHex('EF4039FB'),
      }).toString('hex')) // A9AC67832330
      console.log(Crypto1.mfkey32v2({
      uid: '65535D33',
      nt0: 'CB7B9ED9',
      nr0: '5A8FFEC6',
      ar0: '5C7C6F89',
      nt1: '1E6D9228',
      nr1: '6FB8B4A8',
      ar1: 'EF4039FB',
      }).toString('hex')) // A9AC67832330
    • Recover the key with the successfully authentication between the reader and the tag.

      Parameters

      • opts: {
            ar: string | number | Buffer;
            at: string | number | Buffer;
            nr: string | number | Buffer;
            nt: string | number | Buffer;
            uid: string | number | Buffer;
        }
        • ar: string | number | Buffer

          The random challenge from reader in the authentication.

        • at: string | number | Buffer

          The calculated response of args.ar from tag in the authentication.

        • nr: string | number | Buffer

          The calculated response of args.nt from reader in the authentication.

        • nt: string | number | Buffer

          The nonce from tag in the authentication.

        • uid: string | number | Buffer

          The 4-bytes uid in the authentication.

      Returns Buffer

      The recovered key.

      const { Buffer } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.mfkey32v2({
      uid: 0x65535D33,
      nt: 0x2C198BE4,
      nr: 0xFEDAC6D2,
      ar: 0xCF0A3C7E,
      at: 0xF4A81AF8,
      }).toString('hex')) // A9AC67832330
      console.log(Crypto1.mfkey32v2({
      uid: Buffer.fromHex('65535D33'),
      nt: Buffer.fromHex('2C198BE4'),
      nr: Buffer.fromHex('FEDAC6D2'),
      ar: Buffer.fromHex('CF0A3C7E'),
      at: Buffer.fromHex('F4A81AF8'),
      }).toString('hex')) // A9AC67832330
      console.log(Crypto1.mfkey32v2({
      uid: '65535D33',
      nt: '2C198BE4',
      nr: 'FEDAC6D2',
      ar: 'CF0A3C7E',
      at: 'F4A81AF8',
      }).toString('hex')) // A9AC67832330
    • Recover key from mifare tags with weak prng

      Parameters

      • opts: {
            atks: {
                nt1: string | number | Buffer;
                nt2: string | number | Buffer;
                par: string | number | Buffer;
            }[];
            dist: string
            | number
            | Buffer;
            uid: string | number | Buffer;
        }
        • atks: {
              nt1: string | number | Buffer;
              nt2: string | number | Buffer;
              par: string | number | Buffer;
          }[]

          The logs of the nested attack.

        • dist: string | number | Buffer

          The nonce distance between two authentication.

        • uid: string | number | Buffer

          The 4-bytes uid in the authentication.

      Returns Buffer[]

      candidates keys

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')
      const args = {
      uid: '877209e1',
      dist: '00000080',
      atks: [
      { nt1: 'b4a08a09', nt2: '8a15bbf2', par: 5 },
      { nt1: '1613293d', nt2: '912e6760', par: 7 }
      ]
      }
      const keys = Crypto1.nested(args)
      console.log(`keys = ${JSON.stringify(_.map(keys, key => key.toString('hex')))}`)
    • Generate the new prng state from the current prng state x by n times.

      Parameters

      • x: number

        The current prng state.

      • n: number

        The number of times to generate the new prng state.

      Returns number

      The new prng state.

    • Recover key from mifare tags with static nonce

      Parameters

      • opts: {
            atks: { nt1: string | number | Buffer; nt2: string | number | Buffer }[];
            keyType: Mf1KeyType;
            uid: string | number | Buffer;
        }
        • atks: { nt1: string | number | Buffer; nt2: string | number | Buffer }[]

          The nonce logs of the authentication.

        • keyType: Mf1KeyType

          The key type of target block.

        • uid: string | number | Buffer

          The 4-bytes uid in the authentication.

      Returns Buffer[]

      candidates keys

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')
      const { Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
      const args = {
      uid: 'b908a16d',
      keyType: Mf1KeyType.KEY_A,
      atks: [
      { nt1: '01200145', nt2: '81901975' },
      { nt1: '01200145', nt2: 'cdd400f3' },
      ],
      }
      const keys = Crypto1.staticnested(args)
      console.log(`keys = ${JSON.stringify(_.map(keys, key => key.toString('hex')))}`)

    Internal

    even: number = 0
    odd: number = 0
    evenParityCache: number[] = []
    lfsrBuf: Buffer = ...
    • Internal

      Get bit of the unsigned reversed endian 32-bit integer x at position n.

      Parameters

      • x: number

        The reversed endian unsigned 32-bit integer.

      • n: number

        The bit position.

      Returns number

      The bit at position n.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.beBit(0x01000000, 0)) // 1
    • Internal

      Get bit of the unsigned 32-bit integer x at position n.

      Parameters

      • x: number

        The unsigned 32-bit integer.

      • n: number

        The bit position.

      Returns number

      The bit at position n.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.bit(0x1, 0)) // 1
    • Internal

      Cast Buffer, hex string or number to UInt32

      Parameters

      • x: string | number | Buffer

        Buffer, string or number

      Returns number

      UInt32

    • Internal

      helper function which eliminates possible secret states using parity bits

      Parameters

      • pfx: number
      • ar: number
      • par: number[][]
      • odd: number
      • even: number
      • isZeroPar: boolean

      Returns undefined | Crypto1

    • Internal

      Return the even parity of the unsigned 32-bit integer x.

      Parameters

      • x: number

        The unsigned 32-bit integer.

      Returns number

      The even parity of x.

    • Internal

      Return the even parity of the unsigned 8-bit integer x.

      Parameters

      • x: number

        The unsigned 8-bit integer.

      Returns number

      The even parity of x.

    • Internal

      Using a bit of the keystream extend the table of possible lfsr states. (complex version)

      Parameters

      • tbl: Uint32Array

        An array of the even/odd bits of lfsr.

      • size: number

        Size of array.

      • bit: number

        The bit of the keystream.

      • m1: number

        mask1

      • m2: number

        mask2

      • input: number

        The value that was fed into the lfsr at the time the keystream was generated.

      Returns number

      The new size of array.

    • Internal

      Using a bit of the keystream extend the table of possible lfsr states. (simple version)

      Parameters

      • tbl: Uint32Array

        An array of the even/odd bits of lfsr.

      • size: number

        Size of array.

      • bit: number

        The bit of the keystream.

      Returns number

      The new size of array.

    • Internal

      The filter function of Crypto1.

      Parameters

      • x: number

        The unsigned 32-bit integer.

      Returns number

      The filtered bit.

    • Internal

      Parameters

      • pfx: number
      • ar: number
      • ks: Buffer
      • par: number[][]
      • isZeroPar: boolean

      Returns Crypto1[]

    • Internal

      Parameters

      • ks: Buffer
      • isOdd: boolean

      Returns number[]

    • Internal

      Recover the state of the lfsr given 32 bits of the keystream. Additionally you can use the in parameter to specify the value that was fed into the lfsr at the time the keystream was generated

      Parameters

      • ks2: number
      • input: number

      Returns Crypto1[]

      The array of recovered lfsr states.

    • Internal

      Reverse 64 bits of keystream into possible lfsr states. Variation mentioned in the paper. Somewhat optimized version

      Parameters

      • ks2: number

        keystream 2

      • ks3: number

        keystream 3

      Returns Crypto1

      The recovered lfsr state.

    • Internal

      Recursively narrow down the search space, 4 bits of keystream at a time.

      Parameters

      • ctx: {
            eks: number;
            evens: { d: Uint32Array; s: number };
            input: number;
            odds: { d: Uint32Array; s: number };
            oks: number;
            rem: number;
            states: Crypto1[];
        }
        • eks: number
        • evens: { d: Uint32Array; s: number }

          The array of even bits of possible lfsr states.

        • input: number
        • odds: { d: Uint32Array; s: number }

          The array of odd bits of possible lfsr states.

        • oks: number
        • rem: number
        • states: Crypto1[]

          The array of recovered lfsr states.

      Returns void

    • Internal

      Parameters

      • nt1: number
      • nt2: number
      • ks1: number
      • par: number

      Returns boolean

    • Internal

      Parameters

      • opts: { atks: { ks1: number; ntp: number }[]; uid: number }

      Returns Buffer[]

    • Internal

      Return the odd parity of the unsigned 8-bit integer x.

      Parameters

      • x: number

        The unsigned 8-bit integer.

      Returns number

      The odd parity of x.

    • Internal

      Swap endian of the unsigned 32-bit integer x.

      Parameters

      • x: number

        The unsigned 32-bit integer.

      Returns number

      The unsigned 32-bit integer after swap endian.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.swapEndian(0x12345678).toString(16)) // '78563412'
    • Internal

      Cast the number x to bit.

      Parameters

      • x: number

        The number.

      Returns number

      The casted bit.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.toBit(1)) // 1
      console.log(Crypto1.toBit(2)) // 0
    • Internal

      Indicates whether the number is truly or not.

      Parameters

      • x: number

        The number.

      Returns number

      Return 1 if the number is not falsey, otherwise return 0.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.toBool(1)) // 1
      console.log(Crypto1.toBool(2)) // 1
    • Internal

      Cast the number x to unsigned 24-bit integer.

      Parameters

      • x: number

        The number.

      Returns number

      The casted unsigned 24-bit integer.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.toUint24(-1).toString(16)) // 'ffffff'
    • Internal

      Cast the number x to unsigned 32-bit integer.

      Parameters

      • x: number

        The number.

      Returns number

      The casted unsigned 32-bit integer.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.toUint32(-1).toString(16)) // 'ffffffff'
    • Internal

      Cast the number x to unsigned 8-bit integer.

      Parameters

      • x: number

        The number.

      Returns number

      The casted unsigned 8-bit integer.

      const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1.mjs/+esm')

      console.log(Crypto1.toUint8(-1).toString(16)) // 'ff'
    • Internal

      A helper function to calculates the partial linear feedback contributions and puts in MSB (Most Significant Bit).

      Parameters

      • item: number

        The input number.

      • mask1: number
      • mask2: number

      Returns number