JavaScript implementation of the Crypto1 cipher.

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.

        • (attempt): Promise<{
              ar: Buffer;
              ks: Buffer;
              nr: Buffer;
              nt: Buffer;
              par: Buffer;
              uid: Buffer;
          }>
        • Parameters

          • attempt: number

          Returns Promise<{
              ar: Buffer;
              ks: Buffer;
              nr: Buffer;
              nt: Buffer;
              par: Buffer;
              uid: Buffer;
          }>

    • 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: UInt32Like;
          nt: UInt32Like;
          uid: UInt32Like;
      }
      • data: Buffer

        The encrypted data.

      • key: Buffer

        The 6-bytes key to decrypt the data.

      • nr: UInt32Like

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

      • nt: UInt32Like

        The nonce from tag in the authentication.

      • uid: UInt32Like

        The 4-bytes uid in the authentication.

    Returns Buffer

    The decrypted data.

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

    Parameters

    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: UInt32Like;
          ar1: UInt32Like;
          nr0: UInt32Like;
          nr1: UInt32Like;
          nt0: UInt32Like;
          nt1: UInt32Like;
          uid: UInt32Like;
      }
      • ar0: UInt32Like

        The random challenge from reader in the first authentication attempt.

      • ar1: UInt32Like

        The random challenge from reader in the second authentication attempt.

      • nr0: UInt32Like

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

      • nr1: UInt32Like

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

      • nt0: UInt32Like

        The nonce from tag in the first authentication attempt.

      • nt1: UInt32Like

        The nonce from tag in the second authentication attempt.

      • uid: UInt32Like

        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

    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

    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

    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

    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

    Parameters

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

    Returns boolean

  • Internal

    Parameters

    • opts: {
          atks: {
              ks1: number;
              ntp: number;
          }[];
          uid: number;
      }
      • 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

MMNEPVFCICPMFPCPTTAAATR