passforios/passKit/Helpers/YubiKeyAPDU.swift
2023-03-09 11:40:33 -08:00

87 lines
3 KiB
Swift

//
// YubiKeyAPDU.swift
// passKit
//
// Copyright © 2022 Bob Sun. All rights reserved.
//
import YubiKit
public enum YubiKeyAPDU {
public static func selectOpenPGPApplication() -> YKFSelectApplicationAPDU {
let selectOpenPGPAPDU = YKFSelectApplicationAPDU(data: Data([0xD2, 0x76, 0x00, 0x01, 0x24, 0x01]))!
return selectOpenPGPAPDU
}
public static func verify(password: String) -> YKFAPDU {
let pw1: [UInt8] = Array(password.utf8)
var apdu: [UInt8] = []
apdu += [0x00] // CLA
apdu += [0x20] // INS: VERIFY
apdu += [0x00] // P1
apdu += [0x82] // P2: PW1
apdu += withUnsafeBytes(of: UInt8(pw1.count).bigEndian, Array.init)
apdu += pw1
let verifyApdu = YKFAPDU(data: Data(apdu))!
return verifyApdu
}
public static func decipherExtended(data: Data) -> [YKFAPDU] {
var apdu: [UInt8] = []
apdu += [0x00] // CLA (last or only command of a chain)
apdu += [0x2A, 0x80, 0x86] // INS, P1, P2: PSO.DECIPHER
// Lc, An extended Lc field consists of three bytes:
// one byte set to '00' followed by two bytes not set to '0000' (1 to 65535 dec.).
apdu += [0x00] + withUnsafeBytes(of: UInt16(data.count + 1).bigEndian, Array.init)
// Padding indicator byte (00) for RSA or (02) for AES followed by cryptogram Cipher DO 'A6' for ECDH
apdu += [0x00]
apdu += data
apdu += [0x02, 0x00]
return [YKFAPDU(data: Data(apdu))!]
}
public static func decipherChained(data: Data) -> [YKFAPDU] {
var result: [YKFAPDU] = []
let chunks = chunk(data: data)
for chunk in chunks.dropLast() {
var apdu: [UInt8] = []
apdu += [0x10] // CLA (command is not the last command of a chain)
apdu += [0x2A, 0x80, 0x86] // INS, P1, P2: PSO.DECIPHER
apdu += withUnsafeBytes(of: UInt8(chunk.count).bigEndian, Array.init)
apdu += chunk
result += [YKFAPDU(data: Data(apdu))!]
}
var apdu: [UInt8] = []
apdu += [0x00] // CLA (last or only command of a chain)
apdu += [0x2A, 0x80, 0x86] // INS, P1, P2: PSO.DECIPHER
apdu += withUnsafeBytes(of: UInt8(chunks.last!.count).bigEndian, Array.init)
apdu += chunks.last!
apdu += [0x00] // Le
result += [YKFAPDU(data: Data(apdu))!]
return result
}
public static func get_application_related_data() -> YKFAPDU {
var apdu: [UInt8] = []
apdu += [0x00] // CLA
apdu += [0xCA] // INS: GET DATA
apdu += [0x00]
apdu += [0x6E] // P2: application related data
apdu += [0x00]
return YKFAPDU(data: Data(apdu))!
}
static func chunk(data: Data) -> [[UInt8]] {
// starts with 00 padding
let padded: [UInt8] = [0x00] + data
let MAX_SIZE = 254
return stride(from: 0, to: padded.count, by: MAX_SIZE).map {
Array(padded[$0 ..< Swift.min($0 + MAX_SIZE, padded.count)])
}
}
}