Skip to content

Commit

Permalink
Merge pull request #27 from network-international/avoid_keychain
Browse files Browse the repository at this point in the history
Update keychain usage, remove obsolete method
  • Loading branch information
akiselevn authored Jan 25, 2024
2 parents aa2f987 + 44e0469 commit 5f902da
Show file tree
Hide file tree
Showing 18 changed files with 385 additions and 398 deletions.
2 changes: 1 addition & 1 deletion CardManagementSDK/Public/NICardManagementAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public final class NICardManagementAPI {
completion(nil, error){}
}
if let response = response {
let result = NICardDetailsResponse(clearPan: response.cardNumber, maskedPan: response.maskedPan, expiry: response.expiryDate, clearCVV2: response.cvv2, cardholderName: response.holderName)
let result = NICardDetailsResponse(clearPan: response.cardNumber, maskedPan: response.maskedPan, expiry: response.expiryDate, clearCVV2: response.cvv2, cardholderName: response.cardholderName)
completion(result, nil){}
}
}
Expand Down
25 changes: 12 additions & 13 deletions CardManagementSDK/Source/Models/PinEncryption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,29 @@
import Foundation

struct PinEncryption {
var pin: String
var pan: String
var certificate: String
let pin: String
let pan: String
let certificate: String

var encryptedPinBlock: String? {
/// Create pin block
let pinBlock = PinBlock.createPinBlock(pin, pan)
/// Encrypt pin block
let encrypted = encryptPin(pinBlock, certificate: certificate)
return encrypted
}
let encryptedPinBlock: String

let method: String = "ASYMMETRIC_ENC"
let algorithm: String = "" // TODO: will be a constant value; IT IS NOT USED YET IN THE API - no need to send it in the request body

init(pin: String, pan: String, certificate: String) {
init(pin: String, pan: String, certificate: String) throws {
self.pin = pin
self.pan = pan
self.certificate = certificate

/// Create pin block
let pinBlock = PinBlock.createPinBlock(pin, pan)
/// Encrypt pin block
encryptedPinBlock = try Self.encryptPin(pinBlock, certificate: certificate)
}

/// Create & encrypt pin block
private func encryptPin(_ pinBlock: String, certificate: String) -> String? {
let encryptedPinBlock = RSAUtils.encrypt(string: pinBlock, certificate: certificate)
private static func encryptPin(_ pinBlock: String, certificate: String) throws -> String {
let encryptedPinBlock = try RSAUtils.encrypt(string: pinBlock, certificate: certificate)
return encryptedPinBlock
}

Expand Down
135 changes: 77 additions & 58 deletions CardManagementSDK/Source/Network/NIMobileAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class NIMobileAPI {
private let cardIdentifierType: String
private let bankCode: String

private var rsaKeysProvider: () -> RSAKeyx509?
private var rsaKeysProvider: () throws -> RSAKeyx509
private let logger: NICardManagementLogger?


Expand All @@ -37,18 +37,24 @@ class NIMobileAPI {
self.rootUrl = rootUrl
self.logger = logger
rsaKeysProvider = {
RSA.generatePublicKeyx509() // regenerate on each keys request
// regenerate on each keys request
let tag = "com.\(Bundle.sdkBundle.bundleIdentifier ?? "NISDK").keys.\(bankCode)".data(using: .utf8)!
return try RSA.generateRSAKeyx509(tag: tag, isPermanent: false)
}
}

func retrieveCardDetails(completion: @escaping (CardDetailsResponse?, NIErrorResponse?) -> Void) {

guard let publicKey = rsaKeysProvider() else {
let rsaInfo: RSAKeyx509
do {
rsaInfo = try rsaKeysProvider()
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.RSAKEY_ERROR))
return
}


let cardParams = CardDetailsParams(publicKey: publicKey.value)
let cardParams = CardDetailsParams(publicKey: rsaInfo.cert)
let requestBuilder: (NIConnectionProperties, RequestLogger) -> Request = { [cardParams, cardIdentifierId, cardIdentifierType, bankCode] connectionProperties, requestLogger in
Request(.cardDetails(
cardParams: cardParams,
Expand All @@ -58,47 +64,51 @@ class NIMobileAPI {
connection: connectionProperties
), logger: requestLogger)
}
sendRequest(builder: requestBuilder) { response, error in

sendRequest(builder: requestBuilder) { [privKey = rsaInfo.privateKey] response, error in
guard let response = response else {
if error != nil {
completion(nil, error)
}
return
}

guard let data = response.data else {
completion(nil, NIErrorResponse(error: NISDKErrors.NETWORK_ERROR))
return
}

if let cardDetails = CardDetailsResponse(json: data, privateKeychainTag: publicKey.privateKeychainTag) {
do {
let cardDetails = try CardDetailsResponse(json: data, privateKey: privKey)
completion(cardDetails, error)
} else {
} catch {
// logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PARSING_ERROR))
}

}
}

func cardLookup(completion: @escaping (CardLookupResponse?, NIErrorResponse?) -> Void) {

guard let publicKey = rsaKeysProvider() else {
let rsaInfo: RSAKeyx509
do {
rsaInfo = try rsaKeysProvider()
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.RSAKEY_ERROR))
return
}

let params = CardLookupParams(
cardIdentifierId: cardIdentifierId,
cardIdentifierType: cardIdentifierType,
publicKey: publicKey.value
publicKey: rsaInfo.cert
)
let requestBuilder: (NIConnectionProperties, RequestLogger) -> Request = { [params, bankCode] connectionProperties, requestLogger in
Request(
.cardsLookup(lookupParams: params, bankCode: bankCode, connection: connectionProperties),
logger: requestLogger
)
}
sendRequest(builder: requestBuilder) { response, error in
sendRequest(builder: requestBuilder) { [privKey = rsaInfo.privateKey] response, error in
guard let response = response else {
completion(nil, error)
return
Expand All @@ -108,10 +118,11 @@ class NIMobileAPI {
completion(nil, NIErrorResponse(error: NISDKErrors.NETWORK_ERROR))
return
}

if let res = CardLookupResponse(json: data, privateKeychainTag: publicKey.privateKeychainTag) {
do {
let res = try CardLookupResponse(json: data, privateKey: privKey)
completion(res, error)
} else {
} catch {
// logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PARSING_ERROR))
}
}
Expand All @@ -132,25 +143,28 @@ class NIMobileAPI {
completion(nil, NIErrorResponse(error: NISDKErrors.NETWORK_ERROR))
return
}

if let res = PinCertificateResponse().parse(json: data) {
do {
let res = try PinCertificateResponse(json: data)
completion(res, error)
} else {
} catch {
// logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PARSING_ERROR))
}

}
}

func retrievePin(completion: @escaping (ViewPinResponse?, NIErrorResponse?) -> Void) {

guard let publicKey = rsaKeysProvider() else {
let rsaInfo: RSAKeyx509
do {
rsaInfo = try rsaKeysProvider()
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.RSAKEY_ERROR))
return
}

let params = ViewPinParams(
publicKey: publicKey.value,
publicKey: rsaInfo.cert,
cardIdentifierId: cardIdentifierId,
cardIdentifierType: cardIdentifierType
)
Expand All @@ -161,7 +175,7 @@ class NIMobileAPI {
connection: connectionProperties
), logger: requestLogger)
}
sendRequest(builder: requestBuilder) { response, error in
sendRequest(builder: requestBuilder) { [privKey = rsaInfo.privateKey] response, error in

guard let response = response else {
completion(nil, error)
Expand All @@ -172,30 +186,32 @@ class NIMobileAPI {
completion(nil, NIErrorResponse(error: NISDKErrors.NETWORK_ERROR))
return
}


if let resp = ViewPinResponse(json: data, privateKeychainTag: publicKey.privateKeychainTag) {
completion(resp, error)
} else {
do {
let res = try ViewPinResponse(json: data, privateKey: privKey)
completion(res, error)
} catch {
// logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PARSING_ERROR))
}

}
}


func setPin(_ encryption: PinEncryption, completion: @escaping (Response?, NIErrorResponse?) -> Void) {

guard let encryptedPin = encryption.encryptedPinBlock else {
func setPin(pin: String, pan: String, certificate: String, completion: @escaping (Response?, NIErrorResponse?) -> Void) {
let pinEncryption: PinEncryption
do {
pinEncryption = try PinEncryption(pin: pin, pan: pan, certificate: certificate)
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PINBLOCK_ENCRYPTION_ERROR))
return
}

let params = PinParams(
cardIdentifierId: cardIdentifierId,
cardIdentifierType: cardIdentifierType,
encryptedPin: encryptedPin,
encryptionMethod: encryption.method
encryptedPin: pinEncryption.encryptedPinBlock,
encryptionMethod: pinEncryption.method
)
let requestBuilder: (NIConnectionProperties, RequestLogger) -> Request = { [params, bankCode] connectionProperties, requestLogger in
Request(.setPin(
Expand All @@ -207,18 +223,21 @@ class NIMobileAPI {
sendRequest(builder: requestBuilder, completion: completion)
}

func verifyPin(_ encryption: PinEncryption, completion: @escaping (Response?, NIErrorResponse?) -> Void) {

guard let encryptedPin = encryption.encryptedPinBlock else {
func verifyPin(pin: String, pan: String, certificate: String, completion: @escaping (Response?, NIErrorResponse?) -> Void) {
let pinEncryption: PinEncryption
do {
pinEncryption = try PinEncryption(pin: pin, pan: pan, certificate: certificate)
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PINBLOCK_ENCRYPTION_ERROR))
return
}

let params = PinParams(
cardIdentifierId: cardIdentifierId,
cardIdentifierType: cardIdentifierType,
encryptedPin: encryptedPin,
encryptionMethod: encryption.method
encryptedPin: pinEncryption.encryptedPinBlock,
encryptionMethod: pinEncryption.method
)
let requestBuilder: (NIConnectionProperties, RequestLogger) -> Request = { [params, bankCode] connectionProperties, requestLogger in
Request(.verifyPin(
Expand All @@ -230,18 +249,24 @@ class NIMobileAPI {
sendRequest(builder: requestBuilder, completion: completion)
}

func changePin(_ encryption: (PinEncryption, PinEncryption), completion: @escaping (Response?, NIErrorResponse?) -> Void) {

guard let encryptedOldPin = encryption.0.encryptedPinBlock, let encryptedPin = encryption.1.encryptedPinBlock else {
func changePin(oldPin: String, newPin: String, pan: String, certificate: String, completion: @escaping (Response?, NIErrorResponse?) -> Void) {
let oldPinEncryption: PinEncryption
let newPinEncryption: PinEncryption
do {
oldPinEncryption = try PinEncryption(pin: oldPin, pan: pan, certificate: certificate)
newPinEncryption = try PinEncryption(pin: newPin, pan: pan, certificate: certificate)
} catch {
logger?.logNICardManagementMessage("RSA error \(error)")
completion(nil, NIErrorResponse(error: NISDKErrors.PINBLOCK_ENCRYPTION_ERROR))
return
}

let params = ChangePinParams(
cardIdentifierId: cardIdentifierId,
cardIdentifierType: cardIdentifierType,
encryptedOldPin: encryptedOldPin,
encryptedNewPin: encryptedPin,
encryptionMethod: encryption.0.method
encryptedOldPin: oldPinEncryption.encryptedPinBlock,
encryptedNewPin: newPinEncryption.encryptedPinBlock,
encryptionMethod: newPinEncryption.method
)
let requestBuilder: (NIConnectionProperties, RequestLogger) -> Request = { [params, bankCode] connectionProperties, requestLogger in
Request(.changePin(
Expand Down Expand Up @@ -329,9 +354,8 @@ extension NIMobileAPI {
return
}
/// 3. create and encrypt pin block
let pinEncryption = PinEncryption(pin: pin, pan: clearPan, certificate: certificate)
/// 4. set pin
self.setPin(pinEncryption) { response, error in
self.setPin(pin: pin, pan: clearPan, certificate: certificate) { response, error in
if let error = error {
completion(nil, error)
} else if response != nil {
Expand All @@ -357,9 +381,8 @@ extension NIMobileAPI {
return
}
/// 3. create and encrypt pin block
let pinEncryption = PinEncryption(pin: pin, pan: clearPan, certificate: certificate)
/// 4. set pin
self.verifyPin(pinEncryption) { response, error in
self.verifyPin(pin: pin, pan: clearPan, certificate: certificate) { response, error in
if let error = error {
completion(nil, error)
} else if response != nil {
Expand All @@ -384,12 +407,8 @@ extension NIMobileAPI {
completion(nil, error)
return
}
/// 3. create and encrypt old pin block
let oldPinEncryption = PinEncryption(pin: oldPin, pan: clearPan, certificate: certificate)
/// 4. create and encrypt new pin block
let newPinEncryption = PinEncryption(pin: newPin, pan: clearPan, certificate: certificate)
/// 4. set pin
self.changePin((oldPinEncryption, newPinEncryption)) { response, error in
/// 3. set pin
self.changePin(oldPin: oldPin, newPin: newPin, pan: clearPan, certificate: certificate) { response, error in
if let error = error {
completion(nil, error)
} else if response != nil {
Expand Down
Loading

0 comments on commit 5f902da

Please sign in to comment.