@trustchex/react-native-sdk 1.409.0 → 1.464.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +59 -1
- package/ios/Camera/TrustchexCameraView.swift +9 -1
- package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
- package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
- package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
- package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +102 -23
- package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
- package/lib/module/Screens/Dynamic/VideoCallScreen.js +3 -1
- package/lib/module/Screens/Static/ResultScreen.js +128 -22
- package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
- package/lib/module/Shared/Animations/recording.json +1 -0
- package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
- package/lib/module/Shared/Components/EIDScanner.js +212 -108
- package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -36
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
- package/lib/module/Shared/Components/NavigationManager.js +24 -16
- package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
- package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
- package/lib/module/Shared/EIDReader/bacKey.js +16 -2
- package/lib/module/Shared/EIDReader/eidReader.js +354 -13
- package/lib/module/Shared/EIDReader/eidService.js +25 -1
- package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
- package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
- package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
- package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
- package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
- package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
- package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
- package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
- package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
- package/lib/module/Shared/Libs/analytics.utils.js +4 -0
- package/lib/module/Shared/Libs/contains.js +1 -40
- package/lib/module/Shared/Libs/country-display.utils.js +34 -0
- package/lib/module/Shared/Libs/demo.utils.js +8 -0
- package/lib/module/Shared/Libs/mrz.utils.js +3 -2
- package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
- package/lib/module/Shared/Types/analytics.types.js +2 -0
- package/lib/module/Translation/Resources/en.js +41 -2
- package/lib/module/Translation/Resources/tr.js +41 -2
- package/lib/module/Trustchex.js +54 -20
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
- package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +40 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +40 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/Trustchex.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +7 -4
- package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
- package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
- package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
- package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +124 -23
- package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
- package/src/Screens/Dynamic/VideoCallScreen.tsx +3 -1
- package/src/Screens/Static/ResultScreen.tsx +183 -31
- package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
- package/src/Shared/Animations/recording.json +1 -0
- package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
- package/src/Shared/Components/EIDScanner.tsx +222 -111
- package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
- package/src/Shared/Components/IdentityDocumentCamera.tsx +199 -184
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
- package/src/Shared/Components/NavigationManager.tsx +27 -18
- package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
- package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
- package/src/Shared/EIDReader/bacKey.ts +24 -8
- package/src/Shared/EIDReader/eidReader.ts +398 -12
- package/src/Shared/EIDReader/eidService.ts +49 -1
- package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
- package/src/Shared/EIDReader/paceInfo.ts +159 -0
- package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
- package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
- package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
- package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
- package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
- package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
- package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
- package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
- package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
- package/src/Shared/Libs/analytics.utils.ts +4 -0
- package/src/Shared/Libs/contains.ts +0 -53
- package/src/Shared/Libs/country-display.utils.ts +55 -0
- package/src/Shared/Libs/crypto.utils.ts +2 -2
- package/src/Shared/Libs/demo.utils.ts +10 -0
- package/src/Shared/Libs/http-client.ts +12 -4
- package/src/Shared/Libs/mrz.utils.ts +3 -2
- package/src/Shared/Libs/status-bar.utils.ts +4 -2
- package/src/Shared/Services/VideoSessionService.ts +1 -1
- package/src/Shared/Types/analytics.types.ts +2 -0
- package/src/Shared/Types/identificationInfo.ts +11 -0
- package/src/Translation/Resources/en.ts +63 -3
- package/src/Translation/Resources/tr.ts +62 -3
- package/src/Trustchex.tsx +53 -17
- package/src/version.ts +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { SecureMessagingWrapper } from "./secureMessagingWrapper.js";
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
import { aesEncryptCBC, aesDecryptCBC, aesEncryptECB, aesCMAC } from "./utils/aesCrypto.utils.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* AES-based secure messaging wrapper for PACE.
|
|
9
|
+
*
|
|
10
|
+
* Uses AES-CBC for encryption and AES-CMAC for MAC computation,
|
|
11
|
+
* as specified in ICAO Doc 9303 Part 11.
|
|
12
|
+
*/
|
|
13
|
+
export class AESSecureMessagingWrapper extends SecureMessagingWrapper {
|
|
14
|
+
constructor(ksEnc, ksMac, maxTransceiveLength, shouldCheckMAC, ssc) {
|
|
15
|
+
super(ksEnc, ksMac, maxTransceiveLength, shouldCheckMAC, ssc);
|
|
16
|
+
}
|
|
17
|
+
getType() {
|
|
18
|
+
return 'AES';
|
|
19
|
+
}
|
|
20
|
+
getPadLength() {
|
|
21
|
+
return 16;
|
|
22
|
+
}
|
|
23
|
+
getIV() {
|
|
24
|
+
// AES IV is E(ksEnc, SSC)
|
|
25
|
+
const sscHex = Buffer.from(this.getEncodedSendSequenceCounter()).toString('hex');
|
|
26
|
+
const ivHex = aesEncryptECB(sscHex, this.getEncryptionKey());
|
|
27
|
+
return Array.from(Buffer.from(ivHex, 'hex'));
|
|
28
|
+
}
|
|
29
|
+
encrypt(dataHex, keyHex) {
|
|
30
|
+
const ivHex = Buffer.from(this.getIV()).toString('hex');
|
|
31
|
+
return aesEncryptCBC(dataHex, keyHex, ivHex);
|
|
32
|
+
}
|
|
33
|
+
decrypt(dataHex, keyHex) {
|
|
34
|
+
const ivHex = Buffer.from(this.getIV()).toString('hex');
|
|
35
|
+
return aesDecryptCBC(dataHex, keyHex, ivHex);
|
|
36
|
+
}
|
|
37
|
+
computeMAC(dataHex, keyHex) {
|
|
38
|
+
return aesCMAC(dataHex, keyHex);
|
|
39
|
+
}
|
|
40
|
+
getEncodedSendSequenceCounter() {
|
|
41
|
+
// AES uses 16-byte SSC (128-bit counter)
|
|
42
|
+
const ssc = this.getSendSequenceCounter();
|
|
43
|
+
const bytes = new Uint8Array(16);
|
|
44
|
+
let remaining = ssc;
|
|
45
|
+
for (let i = 15; i >= 0; i--) {
|
|
46
|
+
bytes[i] = Number(remaining & 0xffn);
|
|
47
|
+
remaining >>= 8n;
|
|
48
|
+
}
|
|
49
|
+
return bytes;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -69,13 +69,27 @@ export class BACKey {
|
|
|
69
69
|
*/
|
|
70
70
|
getKey() {
|
|
71
71
|
try {
|
|
72
|
-
|
|
73
|
-
return cryptoUtils.computeKeySeed(mrz, 'SHA-1', true);
|
|
72
|
+
return cryptoUtils.computeKeySeed(this.getMRZString(), 'SHA-1', true);
|
|
74
73
|
} catch (gse) {
|
|
75
74
|
throw new Error('Unexpected exception');
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Returns the key seed for PACE, which is the full (non-truncated) SHA-1 hash
|
|
80
|
+
* of the MRZ info. PACE uses the full 20-byte hash unlike BAC which truncates to 16.
|
|
81
|
+
*/
|
|
82
|
+
getKeySeedForPACE() {
|
|
83
|
+
try {
|
|
84
|
+
return cryptoUtils.computeKeySeed(this.getMRZString(), 'SHA-1', false);
|
|
85
|
+
} catch (gse) {
|
|
86
|
+
throw new Error('Unexpected exception');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
getMRZString() {
|
|
90
|
+
return this.documentNumber + MRZInfo.checkDigit(this.documentNumber, false) + this.dateOfBirth + MRZInfo.checkDigit(this.dateOfBirth, false) + this.dateOfExpiry + MRZInfo.checkDigit(this.dateOfExpiry, false);
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
/**
|
|
80
94
|
* Sets the document number.
|
|
81
95
|
*
|
|
@@ -1,35 +1,374 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { BACKey } from "./bacKey.js";
|
|
4
|
+
import { PACEKeySpec } from "./paceKeySpec.js";
|
|
4
5
|
import { NFCManagerCardService } from "./nfcManagerCardService.js";
|
|
5
6
|
import { EIDService } from "./eidService.js";
|
|
6
7
|
import { DG1File } from "./lds/icao/dg1File.js";
|
|
7
8
|
import { DG2File } from "./lds/icao/dg2File.js";
|
|
8
9
|
import { Buffer } from 'buffer';
|
|
9
10
|
import { InputStream } from "./java/inputStream.js";
|
|
11
|
+
|
|
12
|
+
// --- Minimal PNG encoder (pure JS, no native deps) ---
|
|
13
|
+
// Uses deflate stored (uncompressed) blocks for O(n) encoding speed.
|
|
14
|
+
// A naive DCT-based JPEG encoder would be O(n²) and freeze the JS thread
|
|
15
|
+
// on real passport photos (400×500+ pixels).
|
|
16
|
+
|
|
17
|
+
/** Standard CRC32 lookup table */
|
|
18
|
+
const CRC_TABLE = new Uint32Array(256);
|
|
19
|
+
for (let n = 0; n < 256; n++) {
|
|
20
|
+
let c = n;
|
|
21
|
+
for (let k = 0; k < 8; k++) {
|
|
22
|
+
c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1;
|
|
23
|
+
}
|
|
24
|
+
CRC_TABLE[n] = c;
|
|
25
|
+
}
|
|
26
|
+
function crc32(data) {
|
|
27
|
+
let crc = 0xffffffff;
|
|
28
|
+
for (let i = 0; i < data.length; i++) {
|
|
29
|
+
crc = CRC_TABLE[(crc ^ data[i]) & 0xff] ^ crc >>> 8;
|
|
30
|
+
}
|
|
31
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
32
|
+
}
|
|
33
|
+
function adler32(data) {
|
|
34
|
+
let a = 1;
|
|
35
|
+
let b = 0;
|
|
36
|
+
for (let i = 0; i < data.length; i++) {
|
|
37
|
+
a = (a + data[i]) % 65521;
|
|
38
|
+
b = (b + a) % 65521;
|
|
39
|
+
}
|
|
40
|
+
return (b << 16 | a) >>> 0;
|
|
41
|
+
}
|
|
42
|
+
function writeU32BE(arr, offset, val) {
|
|
43
|
+
arr[offset] = val >>> 24 & 0xff;
|
|
44
|
+
arr[offset + 1] = val >>> 16 & 0xff;
|
|
45
|
+
arr[offset + 2] = val >>> 8 & 0xff;
|
|
46
|
+
arr[offset + 3] = val & 0xff;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Encode raw RGB/RGBA pixels as an uncompressed PNG.
|
|
51
|
+
* Uses deflate stored blocks (no compression) for maximum compatibility.
|
|
52
|
+
*/
|
|
53
|
+
function pixelsToPng(pixels, width, height, channels) {
|
|
54
|
+
// Build raw scanlines: filter byte (0) + RGB data per row
|
|
55
|
+
const rawRowLen = 1 + width * 3; // filter byte + RGB
|
|
56
|
+
const rawData = new Uint8Array(rawRowLen * height);
|
|
57
|
+
for (let y = 0; y < height; y++) {
|
|
58
|
+
const rowOff = y * rawRowLen;
|
|
59
|
+
rawData[rowOff] = 0; // filter: None
|
|
60
|
+
for (let x = 0; x < width; x++) {
|
|
61
|
+
const srcIdx = (y * width + x) * channels;
|
|
62
|
+
const dstIdx = rowOff + 1 + x * 3;
|
|
63
|
+
rawData[dstIdx] = pixels[srcIdx]; // R
|
|
64
|
+
rawData[dstIdx + 1] = pixels[srcIdx + 1]; // G
|
|
65
|
+
rawData[dstIdx + 2] = pixels[srcIdx + 2]; // B
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Wrap raw data in zlib stored (uncompressed) format
|
|
70
|
+
const MAX_BLOCK = 65535;
|
|
71
|
+
const numBlocks = Math.ceil(rawData.length / MAX_BLOCK) || 1;
|
|
72
|
+
const zlibSize = 2 + rawData.length + numBlocks * 5 + 4;
|
|
73
|
+
const zlib = new Uint8Array(zlibSize);
|
|
74
|
+
let zOff = 0;
|
|
75
|
+
// zlib header: CMF=0x78 (deflate, 32K window), FLG=0x01 (check bits, no dict, level 0)
|
|
76
|
+
zlib[zOff++] = 0x78;
|
|
77
|
+
zlib[zOff++] = 0x01;
|
|
78
|
+
let remaining = rawData.length;
|
|
79
|
+
let srcOff = 0;
|
|
80
|
+
while (remaining > 0) {
|
|
81
|
+
const blockLen = Math.min(remaining, MAX_BLOCK);
|
|
82
|
+
const isFinal = remaining <= MAX_BLOCK ? 1 : 0;
|
|
83
|
+
zlib[zOff++] = isFinal; // BFINAL + BTYPE=00 (stored)
|
|
84
|
+
zlib[zOff++] = blockLen & 0xff;
|
|
85
|
+
zlib[zOff++] = blockLen >>> 8 & 0xff;
|
|
86
|
+
zlib[zOff++] = ~blockLen & 0xff;
|
|
87
|
+
zlib[zOff++] = ~blockLen >>> 8 & 0xff;
|
|
88
|
+
zlib.set(rawData.subarray(srcOff, srcOff + blockLen), zOff);
|
|
89
|
+
zOff += blockLen;
|
|
90
|
+
srcOff += blockLen;
|
|
91
|
+
remaining -= blockLen;
|
|
92
|
+
}
|
|
93
|
+
// Adler32 of uncompressed data
|
|
94
|
+
const adl = adler32(rawData);
|
|
95
|
+
writeU32BE(zlib, zOff, adl);
|
|
96
|
+
zOff += 4;
|
|
97
|
+
const zlibData = zlib.subarray(0, zOff);
|
|
98
|
+
|
|
99
|
+
// Build PNG chunks
|
|
100
|
+
const PNG_SIG = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
101
|
+
function makeChunk(type, data) {
|
|
102
|
+
const chunk = new Uint8Array(4 + 4 + data.length + 4);
|
|
103
|
+
writeU32BE(chunk, 0, data.length);
|
|
104
|
+
chunk[4] = type.charCodeAt(0);
|
|
105
|
+
chunk[5] = type.charCodeAt(1);
|
|
106
|
+
chunk[6] = type.charCodeAt(2);
|
|
107
|
+
chunk[7] = type.charCodeAt(3);
|
|
108
|
+
chunk.set(data, 8);
|
|
109
|
+
const crcInput = chunk.subarray(4, 8 + data.length);
|
|
110
|
+
writeU32BE(chunk, 8 + data.length, crc32(crcInput));
|
|
111
|
+
return chunk;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// IHDR: width, height, bit depth 8, color type 2 (RGB)
|
|
115
|
+
const ihdrData = new Uint8Array(13);
|
|
116
|
+
writeU32BE(ihdrData, 0, width);
|
|
117
|
+
writeU32BE(ihdrData, 4, height);
|
|
118
|
+
ihdrData[8] = 8; // bit depth
|
|
119
|
+
ihdrData[9] = 2; // color type: RGB
|
|
120
|
+
ihdrData[10] = 0; // compression
|
|
121
|
+
ihdrData[11] = 0; // filter
|
|
122
|
+
ihdrData[12] = 0; // interlace
|
|
123
|
+
|
|
124
|
+
const ihdrChunk = makeChunk('IHDR', ihdrData);
|
|
125
|
+
const idatChunk = makeChunk('IDAT', zlibData);
|
|
126
|
+
const iendChunk = makeChunk('IEND', new Uint8Array(0));
|
|
127
|
+
const png = new Uint8Array(PNG_SIG.length + ihdrChunk.length + idatChunk.length + iendChunk.length);
|
|
128
|
+
let off = 0;
|
|
129
|
+
png.set(PNG_SIG, off);
|
|
130
|
+
off += PNG_SIG.length;
|
|
131
|
+
png.set(ihdrChunk, off);
|
|
132
|
+
off += ihdrChunk.length;
|
|
133
|
+
png.set(idatChunk, off);
|
|
134
|
+
off += idatChunk.length;
|
|
135
|
+
png.set(iendChunk, off);
|
|
136
|
+
return png;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* If the image is JPEG 2000, decode and convert to PNG so React Native can display it.
|
|
141
|
+
* Returns { base64, mimeType } with the converted image, or the original if not JP2.
|
|
142
|
+
*/
|
|
143
|
+
function convertJP2IfNeeded(imageBuffer, mimeType) {
|
|
144
|
+
if (mimeType !== 'image/jp2') {
|
|
145
|
+
return {
|
|
146
|
+
base64: imageBuffer.toString('base64'),
|
|
147
|
+
mimeType
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
console.debug('[EID] Face image is JP2, attempting conversion…');
|
|
151
|
+
try {
|
|
152
|
+
// Lazy-load jpeg2000 to avoid crashing if it fails to import
|
|
153
|
+
const {
|
|
154
|
+
JpxImage
|
|
155
|
+
} = require('jpeg2000');
|
|
156
|
+
const jpx = new JpxImage();
|
|
157
|
+
jpx.parse(imageBuffer);
|
|
158
|
+
const tile = jpx.tiles[0];
|
|
159
|
+
console.debug(`[EID] JP2 decoded: ${tile.width}x${tile.height}, ${jpx.componentsCount} channels, ${tile.items.length} bytes`);
|
|
160
|
+
const pngBytes = pixelsToPng(tile.items, tile.width, tile.height, jpx.componentsCount);
|
|
161
|
+
const pngBase64 = Buffer.from(pngBytes).toString('base64');
|
|
162
|
+
console.debug(`[EID] Converted JP2 → PNG (${pngBytes.length} bytes, ${pngBase64.length} base64 chars)`);
|
|
163
|
+
return {
|
|
164
|
+
base64: pngBase64,
|
|
165
|
+
mimeType: 'image/png'
|
|
166
|
+
};
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.debug('[EID] JP2 conversion failed:', err);
|
|
169
|
+
return {
|
|
170
|
+
base64: imageBuffer.toString('base64'),
|
|
171
|
+
mimeType
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Try to parse PACE OID and parameter ID from EF.CardAccess data.
|
|
178
|
+
* Returns null if no PACE info is found.
|
|
179
|
+
*/
|
|
180
|
+
function parsePACEInfoFromCardAccess(data) {
|
|
181
|
+
try {
|
|
182
|
+
// EF.CardAccess is a SET of SecurityInfo sequences (ASN.1 DER)
|
|
183
|
+
// Each SecurityInfo: SEQUENCE { OID, INTEGER (version), optional INTEGER (parameterId) }
|
|
184
|
+
let offset = 0;
|
|
185
|
+
if (data[offset] === 0x31) {
|
|
186
|
+
// SET tag
|
|
187
|
+
offset++;
|
|
188
|
+
const setLen = readASN1Length(data, offset);
|
|
189
|
+
offset = setLen.nextOffset;
|
|
190
|
+
}
|
|
191
|
+
while (offset < data.length) {
|
|
192
|
+
if (data[offset] !== 0x30) break; // SEQUENCE tag
|
|
193
|
+
offset++;
|
|
194
|
+
const seqLen = readASN1Length(data, offset);
|
|
195
|
+
const seqEnd = seqLen.nextOffset + seqLen.length;
|
|
196
|
+
offset = seqLen.nextOffset;
|
|
197
|
+
|
|
198
|
+
// Read OID
|
|
199
|
+
if (data[offset] !== 0x06) {
|
|
200
|
+
offset = seqEnd;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
offset++;
|
|
204
|
+
const oidLen = readASN1Length(data, offset);
|
|
205
|
+
offset = oidLen.nextOffset;
|
|
206
|
+
const oidBytes = data.subarray(offset, offset + oidLen.length);
|
|
207
|
+
const oid = decodeOID(oidBytes);
|
|
208
|
+
offset += oidLen.length;
|
|
209
|
+
|
|
210
|
+
// Check if this is a PACE OID
|
|
211
|
+
if (oid.startsWith('0.4.0.127.0.7.2.2.4.')) {
|
|
212
|
+
// Read version (INTEGER)
|
|
213
|
+
let parameterId = 13; // default brainpoolP256r1
|
|
214
|
+
if (offset < seqEnd && data[offset] === 0x02) {
|
|
215
|
+
offset++;
|
|
216
|
+
const intLen = readASN1Length(data, offset);
|
|
217
|
+
offset = intLen.nextOffset + intLen.length;
|
|
218
|
+
}
|
|
219
|
+
// Read optional parameterId (INTEGER)
|
|
220
|
+
if (offset < seqEnd && data[offset] === 0x02) {
|
|
221
|
+
offset++;
|
|
222
|
+
const intLen = readASN1Length(data, offset);
|
|
223
|
+
offset = intLen.nextOffset;
|
|
224
|
+
parameterId = 0;
|
|
225
|
+
for (let i = 0; i < intLen.length; i++) {
|
|
226
|
+
parameterId = parameterId << 8 | data[offset + i];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
oid,
|
|
231
|
+
parameterId
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
offset = seqEnd;
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
// Failed to parse, PACE not available
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
function readASN1Length(data, offset) {
|
|
242
|
+
const firstByte = data[offset];
|
|
243
|
+
if ((firstByte & 0x80) === 0) {
|
|
244
|
+
return {
|
|
245
|
+
length: firstByte,
|
|
246
|
+
nextOffset: offset + 1
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const numBytes = firstByte & 0x7f;
|
|
250
|
+
let length = 0;
|
|
251
|
+
for (let i = 0; i < numBytes; i++) {
|
|
252
|
+
length = length << 8 | data[offset + 1 + i];
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
length,
|
|
256
|
+
nextOffset: offset + 1 + numBytes
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function decodeOID(bytes) {
|
|
260
|
+
const components = [];
|
|
261
|
+
components.push(Math.floor(bytes[0] / 40));
|
|
262
|
+
components.push(bytes[0] % 40);
|
|
263
|
+
let value = 0;
|
|
264
|
+
for (let i = 1; i < bytes.length; i++) {
|
|
265
|
+
value = value << 7 | bytes[i] & 0x7f;
|
|
266
|
+
if ((bytes[i] & 0x80) === 0) {
|
|
267
|
+
components.push(value);
|
|
268
|
+
value = 0;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return components.join('.');
|
|
272
|
+
}
|
|
10
273
|
const eidReader = async (documentNumber, dateOfBirth, dateOfExpiry, progressCallback) => {
|
|
11
274
|
let progress = 0;
|
|
12
275
|
const nfcManagerCardService = new NFCManagerCardService();
|
|
13
276
|
const passportService = new EIDService(nfcManagerCardService, EIDService.NORMAL_MAX_TRANSCEIVE_LENGTH, EIDService.DEFAULT_MAX_BLOCKSIZE, false, true);
|
|
14
277
|
try {
|
|
15
278
|
await passportService.open();
|
|
279
|
+
progress = 1;
|
|
280
|
+
if (progressCallback) {
|
|
281
|
+
progressCallback(progress);
|
|
282
|
+
}
|
|
16
283
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
284
|
+
// Try to read EF.CardAccess before selecting applet to check for PACE.
|
|
285
|
+
// Explicitly SELECT MF first so the SFI=0x1C context is correct,
|
|
286
|
+
// regardless of which application the chip activates on power-on.
|
|
287
|
+
let hasPACESucceeded = false;
|
|
288
|
+
try {
|
|
289
|
+
await passportService.sendSelectMF();
|
|
290
|
+
console.debug('[EID] SELECT MF OK');
|
|
291
|
+
} catch (mfErr) {
|
|
292
|
+
const mfMsg = mfErr instanceof Error ? mfErr.message : String(mfErr);
|
|
293
|
+
console.debug(`[EID] SELECT MF failed (${mfMsg}), continuing with SFI read anyway`);
|
|
294
|
+
}
|
|
295
|
+
progress = 2;
|
|
20
296
|
if (progressCallback) {
|
|
21
297
|
progressCallback(progress);
|
|
22
298
|
}
|
|
23
299
|
|
|
24
|
-
//
|
|
300
|
+
// Read EF.CardAccess — kept in a separate try/catch so we can distinguish
|
|
301
|
+
// "file read failure" from "PACE protocol failure" in the logs.
|
|
302
|
+
let cardAccessBuf = null;
|
|
25
303
|
try {
|
|
26
|
-
const
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
304
|
+
const cardAccessStream = passportService.getInputStream(EIDService.EF_CARD_ACCESS);
|
|
305
|
+
await cardAccessStream.init();
|
|
306
|
+
const cardAccessLen = cardAccessStream.getLength();
|
|
307
|
+
const buf = Buffer.alloc(cardAccessLen);
|
|
308
|
+
for (let i = 0; i < cardAccessLen; i++) {
|
|
309
|
+
buf[i] = await cardAccessStream.read();
|
|
310
|
+
}
|
|
311
|
+
cardAccessBuf = buf;
|
|
312
|
+
console.debug(`[EID] EF.CardAccess read OK: ${cardAccessLen} bytes = ${cardAccessBuf.toString('hex')}`);
|
|
313
|
+
} catch (readErr) {
|
|
314
|
+
const readMsg = readErr instanceof Error ? readErr.message : String(readErr);
|
|
315
|
+
console.debug(`[EID] EF.CardAccess read FAILED: ${readMsg} — falling back to BAC`);
|
|
316
|
+
}
|
|
317
|
+
progress = 3;
|
|
318
|
+
if (progressCallback) {
|
|
319
|
+
progressCallback(progress);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// If EF.CardAccess was read successfully, attempt PACE.
|
|
323
|
+
if (cardAccessBuf !== null) {
|
|
324
|
+
try {
|
|
325
|
+
const paceInfo = parsePACEInfoFromCardAccess(cardAccessBuf);
|
|
326
|
+
if (paceInfo) {
|
|
327
|
+
console.debug(`[EID] PACE available: oid=${paceInfo.oid} parameterId=${paceInfo.parameterId}`);
|
|
328
|
+
// PACE is available - derive key from MRZ and perform PACE
|
|
329
|
+
const bacKey = new BACKey(documentNumber, dateOfBirth, dateOfExpiry);
|
|
330
|
+
const paceKey = PACEKeySpec.createMRZKey(bacKey.getKeySeedForPACE());
|
|
331
|
+
progress = 4;
|
|
332
|
+
if (progressCallback) {
|
|
333
|
+
progressCallback(progress);
|
|
334
|
+
}
|
|
335
|
+
await passportService.doPACE(paceKey, paceInfo.oid, paceInfo.parameterId, progressCallback);
|
|
336
|
+
hasPACESucceeded = true;
|
|
337
|
+
console.debug('[EID] PACE succeeded');
|
|
338
|
+
} else {
|
|
339
|
+
console.debug('[EID] EF.CardAccess read OK but no PACE SecurityInfo found — document does not support PACE, falling back to BAC');
|
|
340
|
+
}
|
|
341
|
+
} catch (paceError) {
|
|
342
|
+
// PACE protocol exchange failed — fall back to BAC
|
|
343
|
+
const msg = paceError instanceof Error ? paceError.message : String(paceError);
|
|
344
|
+
console.debug(`[EID] PACE protocol failed (${msg}), falling back to BAC`);
|
|
345
|
+
if (paceError instanceof Error && paceError.stack) {
|
|
346
|
+
console.debug('[EID] PACE error stack:', paceError.stack);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
progress = 9;
|
|
351
|
+
if (progressCallback) {
|
|
352
|
+
progressCallback(progress);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Select Applet for MRTD
|
|
356
|
+
await passportService.sendSelectApplet(hasPACESucceeded);
|
|
357
|
+
progress = 10;
|
|
358
|
+
if (progressCallback) {
|
|
359
|
+
progressCallback(progress);
|
|
360
|
+
}
|
|
361
|
+
if (!hasPACESucceeded) {
|
|
362
|
+
// Check if EF_COM is available
|
|
363
|
+
try {
|
|
364
|
+
const efComStream = passportService.getInputStream(EIDService.EF_COM);
|
|
365
|
+
await efComStream.init();
|
|
366
|
+
await efComStream.read();
|
|
367
|
+
} catch (error) {
|
|
368
|
+
// EF_COM not available -> try to do BAC
|
|
369
|
+
const bacKey = new BACKey(documentNumber, dateOfBirth, dateOfExpiry);
|
|
370
|
+
await passportService.doBAC(bacKey);
|
|
371
|
+
}
|
|
33
372
|
}
|
|
34
373
|
progress = 20;
|
|
35
374
|
if (progressCallback) {
|
|
@@ -69,8 +408,10 @@ const eidReader = async (documentNumber, dateOfBirth, dateOfExpiry, progressCall
|
|
|
69
408
|
const imageInputStream = await faceImageInfo.getImageInputStream();
|
|
70
409
|
const buffer = Buffer.alloc(imageLength);
|
|
71
410
|
await imageInputStream.readBytesWithOffset(buffer, 0, imageLength);
|
|
72
|
-
|
|
73
|
-
|
|
411
|
+
const rawMimeType = faceImageInfo.getMimeType();
|
|
412
|
+
const converted = convertJP2IfNeeded(buffer, rawMimeType);
|
|
413
|
+
imageAsBase64 = converted.base64;
|
|
414
|
+
mimeType = converted.mimeType;
|
|
74
415
|
}
|
|
75
416
|
progress = 100;
|
|
76
417
|
if (progressCallback) {
|
|
@@ -6,6 +6,8 @@ import { DefaultFileSystem } from "./defaultFileSystem.js";
|
|
|
6
6
|
import { BACAPDUSender } from "./protocol/bacAPDUSender.js";
|
|
7
7
|
import { ReadBinaryAPDUSender } from "./protocol/readBinaryAPDUSender.js";
|
|
8
8
|
import { BACProtocol } from "./protocol/bacProtocol.js";
|
|
9
|
+
import { PACEAPDUSender } from "./protocol/paceAPDUSender.js";
|
|
10
|
+
import { PACEProtocol } from "./protocol/paceProtocol.js";
|
|
9
11
|
import { EID_CONSTANTS } from "./constants/eidConstants.js";
|
|
10
12
|
export class EIDService extends AbstractMRTDCardService {
|
|
11
13
|
/** Shared secret type for non-PACE key. */
|
|
@@ -175,7 +177,13 @@ export class EIDService extends AbstractMRTDCardService {
|
|
|
175
177
|
this.shouldCheckMAC = shouldCheckMAC;
|
|
176
178
|
this.isAppletSelected = false;
|
|
177
179
|
this.isOpen = false;
|
|
178
|
-
|
|
180
|
+
// EF.CardAccess and EF.CardSecurity live in the MF (Master File), outside
|
|
181
|
+
// the ICAO applet. They must be read via SFI-based READ BINARY (no SELECT
|
|
182
|
+
// needed). Without SFI, the implementation falls back to SELECT-by-FID
|
|
183
|
+
// which many passport chips reject at MF level before applet selection,
|
|
184
|
+
// causing PACE to be falsely reported as "not available".
|
|
185
|
+
const rootFidToSFI = new Map([[EID_CONSTANTS.EF_CARD_ACCESS, EID_CONSTANTS.SFI_CARD_ACCESS], [EID_CONSTANTS.EF_CARD_SECURITY, EID_CONSTANTS.SFI_CARD_SECURITY]]);
|
|
186
|
+
this.rootFileSystem = new DefaultFileSystem(this.readBinarySender, true, rootFidToSFI);
|
|
179
187
|
this.appletFileSystem = new DefaultFileSystem(this.readBinarySender, isSFIEnabled);
|
|
180
188
|
}
|
|
181
189
|
async open() {
|
|
@@ -209,6 +217,22 @@ export class EIDService extends AbstractMRTDCardService {
|
|
|
209
217
|
this.appletFileSystem.setWrapper(this.wrapper);
|
|
210
218
|
return bacResult;
|
|
211
219
|
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Performs the PACE protocol.
|
|
223
|
+
*
|
|
224
|
+
* @param accessKey the access key (MRZ or CAN based)
|
|
225
|
+
* @param oid the PACE OID string from EF.CardAccess
|
|
226
|
+
* @param parameterId the standard domain parameter ID (e.g. 13 for brainpoolP256r1)
|
|
227
|
+
*/
|
|
228
|
+
async doPACE(accessKey, oid, parameterId, progressCallback) {
|
|
229
|
+
const paceSender = new PACEAPDUSender(this.service);
|
|
230
|
+
const paceProtocol = new PACEProtocol(paceSender, this.wrapper, EIDService.NORMAL_MAX_TRANSCEIVE_LENGTH, this.maxTransceiveLengthForSecureMessaging, this.shouldCheckMAC);
|
|
231
|
+
const paceResult = await paceProtocol.doPACE(accessKey, oid, parameterId, progressCallback);
|
|
232
|
+
this.wrapper = paceResult.getWrapper();
|
|
233
|
+
this.appletFileSystem.setWrapper(this.wrapper);
|
|
234
|
+
return paceResult;
|
|
235
|
+
}
|
|
212
236
|
async close() {
|
|
213
237
|
try {
|
|
214
238
|
await this.service.close();
|
|
@@ -9,17 +9,16 @@ export class NFCManagerCardService extends CardService {
|
|
|
9
9
|
async open() {
|
|
10
10
|
await NFCManager.start();
|
|
11
11
|
await NFCManager.requestTechnology([NfcTech.IsoDep, NfcTech.NfcA, NfcTech.NfcB]);
|
|
12
|
-
//
|
|
12
|
+
// Increase transceive timeout for slow curves (e.g. brainpoolP512r1 ECDH on passport chip)
|
|
13
|
+
if (Platform.OS === 'android') {
|
|
14
|
+
await NFCManager.setTimeout(10000);
|
|
15
|
+
}
|
|
13
16
|
this.isOpened = true;
|
|
14
17
|
}
|
|
15
18
|
getIsOpen() {
|
|
16
19
|
return this.isOpened;
|
|
17
20
|
}
|
|
18
21
|
async transmit(commandAPDU) {
|
|
19
|
-
// console.debug(
|
|
20
|
-
// `T[${ISO7816_INS[commandAPDU.getINS()]}]:`,
|
|
21
|
-
// Buffer.from(commandAPDU.getBytes()).toString('hex').toUpperCase(),
|
|
22
|
-
// );
|
|
23
22
|
let response;
|
|
24
23
|
if (Platform.OS === 'ios') {
|
|
25
24
|
const iosResponse = await NFCManager.sendCommandAPDUIOS(Array.from(commandAPDU.getBytes()));
|
|
@@ -27,8 +26,6 @@ export class NFCManagerCardService extends CardService {
|
|
|
27
26
|
} else {
|
|
28
27
|
response = await NFCManager.transceive(Array.from(commandAPDU.getBytes()));
|
|
29
28
|
}
|
|
30
|
-
// console.debug('R:', Buffer.from(response).toString('hex').toUpperCase());
|
|
31
|
-
|
|
32
29
|
return new ResponseAPDU(response);
|
|
33
30
|
}
|
|
34
31
|
getATR() {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PACE (Password Authenticated Connection Establishment) protocol info.
|
|
5
|
+
* Parses PACE OIDs to extract mapping type, cipher, digest, key agreement algorithm, and key length.
|
|
6
|
+
*
|
|
7
|
+
* Based on ICAO Doc 9303 Part 11 and BSI TR-03110.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export let MappingType = /*#__PURE__*/function (MappingType) {
|
|
11
|
+
MappingType["GM"] = "GM";
|
|
12
|
+
MappingType["IM"] = "IM";
|
|
13
|
+
MappingType["CAM"] = "CAM";
|
|
14
|
+
return MappingType;
|
|
15
|
+
}({});
|
|
16
|
+
|
|
17
|
+
// PACE OID constants (BSI TR-03110 / ICAO 9303)
|
|
18
|
+
export const ID_PACE = '0.4.0.127.0.7.2.2.4';
|
|
19
|
+
export const ID_PACE_DH_GM = '0.4.0.127.0.7.2.2.4.1';
|
|
20
|
+
export const ID_PACE_DH_GM_3DES_CBC_CBC = '0.4.0.127.0.7.2.2.4.1.1';
|
|
21
|
+
export const ID_PACE_DH_GM_AES_CBC_CMAC_128 = '0.4.0.127.0.7.2.2.4.1.2';
|
|
22
|
+
export const ID_PACE_DH_GM_AES_CBC_CMAC_192 = '0.4.0.127.0.7.2.2.4.1.3';
|
|
23
|
+
export const ID_PACE_DH_GM_AES_CBC_CMAC_256 = '0.4.0.127.0.7.2.2.4.1.4';
|
|
24
|
+
export const ID_PACE_ECDH_GM = '0.4.0.127.0.7.2.2.4.2';
|
|
25
|
+
export const ID_PACE_ECDH_GM_3DES_CBC_CBC = '0.4.0.127.0.7.2.2.4.2.1';
|
|
26
|
+
export const ID_PACE_ECDH_GM_AES_CBC_CMAC_128 = '0.4.0.127.0.7.2.2.4.2.2';
|
|
27
|
+
export const ID_PACE_ECDH_GM_AES_CBC_CMAC_192 = '0.4.0.127.0.7.2.2.4.2.3';
|
|
28
|
+
export const ID_PACE_ECDH_GM_AES_CBC_CMAC_256 = '0.4.0.127.0.7.2.2.4.2.4';
|
|
29
|
+
export const ID_PACE_DH_IM = '0.4.0.127.0.7.2.2.4.3';
|
|
30
|
+
export const ID_PACE_DH_IM_3DES_CBC_CBC = '0.4.0.127.0.7.2.2.4.3.1';
|
|
31
|
+
export const ID_PACE_DH_IM_AES_CBC_CMAC_128 = '0.4.0.127.0.7.2.2.4.3.2';
|
|
32
|
+
export const ID_PACE_DH_IM_AES_CBC_CMAC_192 = '0.4.0.127.0.7.2.2.4.3.3';
|
|
33
|
+
export const ID_PACE_DH_IM_AES_CBC_CMAC_256 = '0.4.0.127.0.7.2.2.4.3.4';
|
|
34
|
+
export const ID_PACE_ECDH_IM = '0.4.0.127.0.7.2.2.4.4';
|
|
35
|
+
export const ID_PACE_ECDH_IM_3DES_CBC_CBC = '0.4.0.127.0.7.2.2.4.4.1';
|
|
36
|
+
export const ID_PACE_ECDH_IM_AES_CBC_CMAC_128 = '0.4.0.127.0.7.2.2.4.4.2';
|
|
37
|
+
export const ID_PACE_ECDH_IM_AES_CBC_CMAC_192 = '0.4.0.127.0.7.2.2.4.4.3';
|
|
38
|
+
export const ID_PACE_ECDH_IM_AES_CBC_CMAC_256 = '0.4.0.127.0.7.2.2.4.4.4';
|
|
39
|
+
export const ID_PACE_ECDH_CAM = '0.4.0.127.0.7.2.2.4.6';
|
|
40
|
+
export const ID_PACE_ECDH_CAM_AES_CBC_CMAC_128 = '0.4.0.127.0.7.2.2.4.6.2';
|
|
41
|
+
export const ID_PACE_ECDH_CAM_AES_CBC_CMAC_192 = '0.4.0.127.0.7.2.2.4.6.3';
|
|
42
|
+
export const ID_PACE_ECDH_CAM_AES_CBC_CMAC_256 = '0.4.0.127.0.7.2.2.4.6.4';
|
|
43
|
+
|
|
44
|
+
// Standard domain parameter identifiers
|
|
45
|
+
export const PARAM_ID_ECP_NIST_P256_R1 = 12;
|
|
46
|
+
export const PARAM_ID_ECP_BRAINPOOL_P256_R1 = 13;
|
|
47
|
+
export const PARAM_ID_ECP_BRAINPOOL_P384_R1 = 16;
|
|
48
|
+
export const PARAM_ID_ECP_BRAINPOOL_P512_R1 = 17;
|
|
49
|
+
export const PARAM_ID_ECP_NIST_P384_R1 = 15;
|
|
50
|
+
export const PARAM_ID_ECP_NIST_P521_R1 = 18;
|
|
51
|
+
const GM_OIDS = new Set([ID_PACE_DH_GM_3DES_CBC_CBC, ID_PACE_DH_GM_AES_CBC_CMAC_128, ID_PACE_DH_GM_AES_CBC_CMAC_192, ID_PACE_DH_GM_AES_CBC_CMAC_256, ID_PACE_ECDH_GM_3DES_CBC_CBC, ID_PACE_ECDH_GM_AES_CBC_CMAC_128, ID_PACE_ECDH_GM_AES_CBC_CMAC_192, ID_PACE_ECDH_GM_AES_CBC_CMAC_256]);
|
|
52
|
+
const IM_OIDS = new Set([ID_PACE_DH_IM_3DES_CBC_CBC, ID_PACE_DH_IM_AES_CBC_CMAC_128, ID_PACE_DH_IM_AES_CBC_CMAC_192, ID_PACE_DH_IM_AES_CBC_CMAC_256, ID_PACE_ECDH_IM_3DES_CBC_CBC, ID_PACE_ECDH_IM_AES_CBC_CMAC_128, ID_PACE_ECDH_IM_AES_CBC_CMAC_192, ID_PACE_ECDH_IM_AES_CBC_CMAC_256]);
|
|
53
|
+
const CAM_OIDS = new Set([ID_PACE_ECDH_CAM_AES_CBC_CMAC_128, ID_PACE_ECDH_CAM_AES_CBC_CMAC_192, ID_PACE_ECDH_CAM_AES_CBC_CMAC_256]);
|
|
54
|
+
const DH_OIDS = new Set([ID_PACE_DH_GM_3DES_CBC_CBC, ID_PACE_DH_GM_AES_CBC_CMAC_128, ID_PACE_DH_GM_AES_CBC_CMAC_192, ID_PACE_DH_GM_AES_CBC_CMAC_256, ID_PACE_DH_IM_3DES_CBC_CBC, ID_PACE_DH_IM_AES_CBC_CMAC_128, ID_PACE_DH_IM_AES_CBC_CMAC_192, ID_PACE_DH_IM_AES_CBC_CMAC_256]);
|
|
55
|
+
const DES_OIDS = new Set([ID_PACE_DH_GM_3DES_CBC_CBC, ID_PACE_DH_IM_3DES_CBC_CBC, ID_PACE_ECDH_GM_3DES_CBC_CBC, ID_PACE_ECDH_IM_3DES_CBC_CBC]);
|
|
56
|
+
const KEY_128_OIDS = new Set([ID_PACE_DH_GM_3DES_CBC_CBC, ID_PACE_DH_IM_3DES_CBC_CBC, ID_PACE_ECDH_GM_3DES_CBC_CBC, ID_PACE_ECDH_IM_3DES_CBC_CBC, ID_PACE_DH_GM_AES_CBC_CMAC_128, ID_PACE_DH_IM_AES_CBC_CMAC_128, ID_PACE_ECDH_GM_AES_CBC_CMAC_128, ID_PACE_ECDH_IM_AES_CBC_CMAC_128, ID_PACE_ECDH_CAM_AES_CBC_CMAC_128]);
|
|
57
|
+
const KEY_192_OIDS = new Set([ID_PACE_DH_GM_AES_CBC_CMAC_192, ID_PACE_DH_IM_AES_CBC_CMAC_192, ID_PACE_ECDH_GM_AES_CBC_CMAC_192, ID_PACE_ECDH_IM_AES_CBC_CMAC_192, ID_PACE_ECDH_CAM_AES_CBC_CMAC_192]);
|
|
58
|
+
const KEY_256_OIDS = new Set([ID_PACE_DH_GM_AES_CBC_CMAC_256, ID_PACE_DH_IM_AES_CBC_CMAC_256, ID_PACE_ECDH_GM_AES_CBC_CMAC_256, ID_PACE_ECDH_IM_AES_CBC_CMAC_256, ID_PACE_ECDH_CAM_AES_CBC_CMAC_256]);
|
|
59
|
+
const SHA256_OIDS = new Set([...KEY_192_OIDS, ...KEY_256_OIDS]);
|
|
60
|
+
export class PACEInfo {
|
|
61
|
+
static toMappingType(oid) {
|
|
62
|
+
if (GM_OIDS.has(oid)) return MappingType.GM;
|
|
63
|
+
if (IM_OIDS.has(oid)) return MappingType.IM;
|
|
64
|
+
if (CAM_OIDS.has(oid)) return MappingType.CAM;
|
|
65
|
+
throw new Error(`Unknown PACE OID: ${oid}`);
|
|
66
|
+
}
|
|
67
|
+
static toKeyAgreementAlgorithm(oid) {
|
|
68
|
+
if (DH_OIDS.has(oid)) return 'DH';
|
|
69
|
+
return 'ECDH';
|
|
70
|
+
}
|
|
71
|
+
static toCipherAlgorithm(oid) {
|
|
72
|
+
if (DES_OIDS.has(oid)) return 'DESede';
|
|
73
|
+
return 'AES';
|
|
74
|
+
}
|
|
75
|
+
static toDigestAlgorithm(oid) {
|
|
76
|
+
if (SHA256_OIDS.has(oid)) return 'SHA-256';
|
|
77
|
+
return 'SHA-1';
|
|
78
|
+
}
|
|
79
|
+
static toKeyLength(oid) {
|
|
80
|
+
if (KEY_128_OIDS.has(oid)) return 128;
|
|
81
|
+
if (KEY_192_OIDS.has(oid)) return 192;
|
|
82
|
+
if (KEY_256_OIDS.has(oid)) return 256;
|
|
83
|
+
throw new Error(`Unknown PACE OID: ${oid}`);
|
|
84
|
+
}
|
|
85
|
+
}
|