Files
self/app/ios/NFCPassportReader/BACHandler.swift
0xturboblitz a45a0f3eb7 Revert "now reading and sending proof"
This reverts commit 1d76de2807.
2023-12-09 17:06:20 -05:00

194 lines
7.2 KiB
Swift

//
// BACHandler.swift
// NFCTest
//
// Created by Andy Qua on 07/06/2019.
// Copyright © 2019 Andy Qua. All rights reserved.
//
import Foundation
#if !os(macOS)
import CoreNFC
@available(iOS 15, *)
public class BACHandler {
let KENC : [UInt8] = [0,0,0,1]
let KMAC : [UInt8] = [0,0,0,2]
public var ksenc : [UInt8] = []
public var ksmac : [UInt8] = []
var rnd_icc : [UInt8] = []
var rnd_ifd : [UInt8] = []
public var kifd : [UInt8] = []
var tagReader : TagReader?
public init() {
// For testing only
}
public init(tagReader: TagReader) {
self.tagReader = tagReader
}
public func performBACAndGetSessionKeys( mrzKey : String ) async throws {
guard let tagReader = self.tagReader else {
throw NFCPassportReaderError.NoConnectedTag
}
Log.debug( "BACHandler - deriving Document Basic Access Keys" )
_ = try self.deriveDocumentBasicAccessKeys(mrz: mrzKey)
// Make sure we clear secure messaging (could happen if we read an invalid DG or we hit a secure error
tagReader.secureMessaging = nil
// get Challenge
Log.debug( "BACHandler - Getting initial challenge" )
let response = try await tagReader.getChallenge()
Log.verbose( "DATA - \(response.data)" )
Log.debug( "BACHandler - Doing mutual authentication" )
let cmd_data = self.authentication(rnd_icc: [UInt8](response.data))
let maResponse = try await tagReader.doMutualAuthentication(cmdData: Data(cmd_data))
Log.debug( "DATA - \(maResponse.data)" )
guard maResponse.data.count > 0 else {
throw NFCPassportReaderError.InvalidMRZKey
}
let (KSenc, KSmac, ssc) = try self.sessionKeys(data: [UInt8](maResponse.data))
tagReader.secureMessaging = SecureMessaging(ksenc: KSenc, ksmac: KSmac, ssc: ssc)
Log.debug( "BACHandler - complete" )
}
func deriveDocumentBasicAccessKeys(mrz: String) throws -> ([UInt8], [UInt8]) {
let kseed = generateInitialKseed(kmrz:mrz)
Log.verbose("Calculate the Basic Access Keys (Kenc and Kmac) using TR-SAC 1.01, 4.2")
let smskg = SecureMessagingSessionKeyGenerator()
self.ksenc = try smskg.deriveKey(keySeed: kseed, mode: .ENC_MODE)
self.ksmac = try smskg.deriveKey(keySeed: kseed, mode: .MAC_MODE)
return (ksenc, ksmac)
}
///
/// Calculate the kseed from the kmrz:
/// - Calculate a SHA-1 hash of the kmrz
/// - Take the most significant 16 bytes to form the Kseed.
/// @param kmrz: The MRZ information
/// @type kmrz: a string
/// @return: a 16 bytes string
///
/// - Parameter kmrz: mrz key
/// - Returns: first 16 bytes of the mrz SHA1 hash
///
func generateInitialKseed(kmrz : String ) -> [UInt8] {
Log.verbose("Calculate the SHA-1 hash of MRZ_information")
Log.verbose("\tMRZ KEY - \(kmrz)")
let hash = calcSHA1Hash( [UInt8](kmrz.data(using:.utf8)!) )
Log.verbose("\tsha1(MRZ_information): \(binToHexRep(hash))")
let subHash = Array(hash[0..<16])
Log.verbose("Take the most significant 16 bytes to form the Kseed")
Log.verbose("\tKseed: \(binToHexRep(subHash))" )
return Array(subHash)
}
/// Construct the command data for the mutual authentication.
/// - Request an 8 byte random number from the MRTD's chip (rnd.icc)
/// - Generate an 8 byte random (rnd.ifd) and a 16 byte random (kifd)
/// - Concatenate rnd.ifd, rnd.icc and kifd (s = rnd.ifd + rnd.icc + kifd)
/// - Encrypt it with TDES and the Kenc key (eifd = TDES(s, Kenc))
/// - Compute the MAC over eifd with TDES and the Kmax key (mifd = mac(pad(eifd))
/// - Construct the APDU data for the mutualAuthenticate command (cmd_data = eifd + mifd)
///
/// @param rnd_icc: The challenge received from the ICC.
/// @type rnd_icc: A 8 bytes binary string
/// @return: The APDU binary data for the mutual authenticate command
func authentication( rnd_icc : [UInt8]) -> [UInt8] {
self.rnd_icc = rnd_icc
Log.verbose("Request an 8 byte random number from the MRTD's chip")
Log.verbose("\tRND.ICC: " + binToHexRep(self.rnd_icc))
self.rnd_icc = rnd_icc
let rnd_ifd = generateRandomUInt8Array(8)
let kifd = generateRandomUInt8Array(16)
Log.verbose("Generate an 8 byte random and a 16 byte random")
Log.verbose("\tRND.IFD: \(binToHexRep(rnd_ifd))" )
Log.verbose("\tRND.Kifd: \(binToHexRep(kifd))")
let s = rnd_ifd + rnd_icc + kifd
Log.verbose("Concatenate RND.IFD, RND.ICC and Kifd")
Log.verbose("\tS: \(binToHexRep(s))")
let iv : [UInt8] = [0, 0, 0, 0, 0, 0, 0, 0]
let eifd = tripleDESEncrypt(key: ksenc,message: s, iv: iv)
Log.verbose("Encrypt S with TDES key Kenc as calculated in Appendix 5.2")
Log.verbose("\tEifd: \(binToHexRep(eifd))")
let mifd = mac(algoName: .DES, key: ksmac, msg: pad(eifd, blockSize:8))
Log.verbose("Compute MAC over eifd with TDES key Kmac as calculated in-Appendix 5.2")
Log.verbose("\tMifd: \(binToHexRep(mifd))")
// Construct APDU
let cmd_data = eifd + mifd
Log.verbose("Construct command data for MUTUAL AUTHENTICATE")
Log.verbose("\tcmd_data: \(binToHexRep(cmd_data))")
self.rnd_ifd = rnd_ifd
self.kifd = kifd
return cmd_data
}
/// Calculate the session keys (KSenc, KSmac) and the SSC from the data
/// received by the mutual authenticate command.
/// @param data: the data received from the mutual authenticate command send to the chip.
/// @type data: a binary string
/// @return: A set of two 16 bytes keys (KSenc, KSmac) and the SSC
public func sessionKeys(data : [UInt8] ) throws -> ([UInt8], [UInt8], [UInt8]) {
Log.verbose("Decrypt and verify received data and compare received RND.IFD with generated RND.IFD \(binToHexRep(self.ksmac))" )
let response = tripleDESDecrypt(key: self.ksenc, message: [UInt8](data[0..<32]), iv: [0,0,0,0,0,0,0,0] )
let response_kicc = [UInt8](response[16..<32])
let Kseed = xor(self.kifd, response_kicc)
Log.verbose("Calculate XOR of Kifd and Kicc")
Log.verbose("\tKseed: \(binToHexRep(Kseed))" )
let smskg = SecureMessagingSessionKeyGenerator()
let KSenc = try smskg.deriveKey(keySeed: Kseed, mode: .ENC_MODE)
let KSmac = try smskg.deriveKey(keySeed: Kseed, mode: .MAC_MODE)
// let KSenc = self.keyDerivation(kseed: Kseed,c: KENC)
// let KSmac = self.keyDerivation(kseed: Kseed,c: KMAC)
Log.verbose("Calculate Session Keys (KSenc and KSmac) using Appendix 5.1")
Log.verbose("\tKSenc: \(binToHexRep(KSenc))" )
Log.verbose("\tKSmac: \(binToHexRep(KSmac))" )
let ssc = [UInt8](self.rnd_icc.suffix(4) + self.rnd_ifd.suffix(4))
Log.verbose("Calculate Send Sequence Counter")
Log.verbose("\tSSC: \(binToHexRep(ssc))" )
return (KSenc, KSmac, ssc)
}
}
#endif