initSession static method

Future<void> initSession({
  1. required DBAKey dbaKeys,
  2. required ICC icc,
})

Implementation

static Future<void> initSession(
    {required DBAKey dbaKeys, required ICC icc}) async {
  _log.debug("🆔 MRZ input for BAC:");
  _log.debug("  Passport number: ${dbaKeys.mrtdNumber}");
  _log.debug("  Date of birth:   ${dbaKeys.dateOfBirth}");
  _log.debug("  Expiry date:     ${dbaKeys.dateOfExpiry}");

  final Kenc = dbaKeys.encKey;
  final Kmac = dbaKeys.macKey;

  // We don't want to see these data in production logs
  _log.sdVerbose("Key seed=${dbaKeys.keySeed.hex()}");
  _log.sdVerbose("Derived Kenc=${Kenc.hex()}");
  _log.sdVerbose("Derived Kmac=${Kmac.hex()}");

  // Get random nonce from ICC
  _log.debug("Requesting challenge from ICC");
  final RNDicc = await icc.getChallenge(challengeLength: nonceLen);
  _log.verbose("Received RND.IC=${RNDicc.hex()}");

  // Generate random RND.IFD & K.IFD
  final RNDifd = randomBytes(nonceLen);
  final Kifd = randomBytes(kLen);
  _log.verbose("Generated RND.IFD=${RNDifd.hex()}");
  _log.sdVerbose("Generated K.IFD=${Kifd.hex()}");

  // Generate S
  final S = generateS(RNDicc: RNDicc, RNDifd: RNDifd, Kifd: Kifd);
  _log.sdVerbose("Generated S=${S.hex()}");

  // Compute cryptogram Eifd and it's mac Mifd
  final Eifd = E(Kenc: Kenc, S: S);
  final Mifd = MAC(Kmac: Kmac, Eifd: Eifd);

  // Execute EXTERNAL AUTHENTICATE command on ICC
  _log.debug("Sending EXTERNAL AUTHENTICATE command");
  _log.verbose("  Eifd=${Eifd.hex()}");
  _log.verbose("  Mifd=${Mifd.hex()}");
  final ICCeaData = await icc.externalAuthenticate(
      data: generateEAData(Eifd: Eifd, Mifd: Mifd), ne: eLen + macLen);

  final pairEiccMicc = extractEiccAndMicc(ICCea_data: ICCeaData);
  _log.verbose("Received from ICC:");
  _log.verbose("  Eicc=${pairEiccMicc.first.hex()}");
  _log.verbose("  Micc=${pairEiccMicc.second.hex()}");

  // Verify MAC of received Eicc
  if (!verifyEicc(
      Eicc: pairEiccMicc.first, Kmac: Kmac, Micc: pairEiccMicc.second)) {
    _log.error("Verifying mac of Eicc failed");
    throw BACError("Verifying mac of Eicc failed");
  }

  // Decrypt R from received Eicc
  _log.debug("Generating session keys KSenc and KSmac");
  final R = D(Kdec: Kenc, Eicc: pairEiccMicc.first);
  _log.verbose("Decrypted R=${R.hex()}");

  // Verify R contains our RND.IFD and extract Kicc from R
  final Kicc = verifyRNDifdAndExtractKicc(RNDifd: RNDifd, R: R);
  _log.sdVerbose("K.ICC=${Kicc.hex()}");

  // Calculate session keys from Kifd and Kicc
  final pairKS = calculateSessionKeys(Kifd: Kifd, Kicc: Kicc);
  _log.sdVerbose("Calculated session keys:");
  _log.sdVerbose("  KSenc=${pairKS.first.hex()}");
  _log.sdVerbose("  KSmac=${pairKS.second.hex()}");

  // Calculate SCC from RND.IFD and RND.ICC
  final ssc = calculateSCC(RNDifd: RNDifd, RNDicc: RNDicc);
  _log.verbose("Calculated SCC=${ssc.toBytes().hex()}");

  _log.debug("Finished BAC SM key establishment");
  icc.sm = MrtdSM(DES_SMCipher(pairKS.first, pairKS.second), ssc);
  _log.debug("SM session is set up");
}