@trustchex/react-native-sdk 1.381.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.
Files changed (204) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
  2. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +60 -13
  3. package/android/src/main/java/com/trustchex/reactnativesdk/mlkit/MLKitModule.kt +1 -1
  4. package/ios/Camera/TrustchexCameraView.swift +10 -13
  5. package/ios/MLKit/MLKitModule.swift +1 -1
  6. package/lib/module/Screens/Debug/BarcodeTestScreen.js +308 -0
  7. package/lib/module/Screens/Debug/MRZTestScreen.js +105 -13
  8. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  9. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +49 -32
  10. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +22 -4
  11. package/lib/module/Screens/Dynamic/IdentityDocumentScanningScreen.js +5 -0
  12. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +126 -27
  13. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  14. package/lib/module/Screens/Dynamic/VideoCallScreen.js +678 -0
  15. package/lib/module/Screens/Static/OTPVerificationScreen.js +6 -0
  16. package/lib/module/Screens/Static/QrCodeScanningScreen.js +7 -1
  17. package/lib/module/Screens/Static/ResultScreen.js +154 -34
  18. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +59 -51
  19. package/lib/module/Shared/Animations/recording.json +1 -0
  20. package/lib/module/Shared/Animations/video-call.json +1 -0
  21. package/lib/module/Shared/Components/DebugNavigationPanel.js +231 -67
  22. package/lib/module/Shared/Components/EIDScanner.js +213 -112
  23. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  24. package/lib/module/Shared/Components/IdentityDocumentCamera.js +77 -39
  25. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  26. package/lib/module/Shared/Components/NavigationManager.js +39 -19
  27. package/lib/module/Shared/Contexts/AppContext.js +1 -0
  28. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  29. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  30. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  31. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  32. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  33. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  34. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  35. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  36. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  37. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  38. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  39. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  40. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  41. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  42. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  43. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  44. package/lib/module/Shared/Libs/SignalingClient.js +128 -0
  45. package/lib/module/Shared/Libs/analytics.utils.js +8 -0
  46. package/lib/module/Shared/Libs/contains.js +1 -40
  47. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  48. package/lib/module/Shared/Libs/deeplink.utils.js +9 -1
  49. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  50. package/lib/module/Shared/Libs/http-client.js +9 -0
  51. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  52. package/lib/module/Shared/Libs/promise.utils.js +16 -2
  53. package/lib/module/Shared/Libs/status-bar.utils.js +23 -0
  54. package/lib/module/Shared/Services/DataUploadService.js +294 -0
  55. package/lib/module/Shared/Services/VideoSessionService.js +156 -0
  56. package/lib/module/Shared/Services/WebRTCService.js +510 -0
  57. package/lib/module/Shared/Types/analytics.types.js +4 -0
  58. package/lib/module/Translation/Resources/en.js +61 -2
  59. package/lib/module/Translation/Resources/tr.js +61 -2
  60. package/lib/module/Trustchex.js +64 -20
  61. package/lib/module/version.js +1 -1
  62. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts +3 -0
  63. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts.map +1 -0
  64. package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts.map +1 -1
  65. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  66. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  67. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  68. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  69. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentScanningScreen.d.ts.map +1 -1
  70. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  71. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  72. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  73. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts +3 -0
  74. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -0
  75. package/lib/typescript/src/Screens/Static/OTPVerificationScreen.d.ts.map +1 -1
  76. package/lib/typescript/src/Screens/Static/QrCodeScanningScreen.d.ts.map +1 -1
  77. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  78. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  79. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  80. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  81. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  82. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  83. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  84. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  85. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  86. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  87. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts +1 -0
  88. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts.map +1 -1
  89. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  90. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  91. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  92. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  93. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  94. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  95. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  96. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  97. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  99. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  100. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  101. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  102. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  103. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  104. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  105. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  106. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  107. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  108. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  109. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  110. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  111. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  112. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  113. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  114. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  115. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts +24 -0
  116. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts.map +1 -0
  117. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  118. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  119. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  120. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  121. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  122. package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts.map +1 -1
  123. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  124. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  125. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  126. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  127. package/lib/typescript/src/Shared/Libs/promise.utils.d.ts.map +1 -1
  128. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts +9 -0
  129. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -0
  130. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts +25 -0
  131. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts.map +1 -0
  132. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts +33 -0
  133. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts.map +1 -0
  134. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts +58 -0
  135. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts.map +1 -0
  136. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +4 -0
  137. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  138. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +13 -1
  139. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  140. package/lib/typescript/src/Translation/Resources/en.d.ts +60 -1
  141. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  142. package/lib/typescript/src/Translation/Resources/tr.d.ts +60 -1
  143. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  144. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  145. package/lib/typescript/src/version.d.ts +1 -1
  146. package/package.json +35 -5
  147. package/src/Screens/Debug/BarcodeTestScreen.tsx +317 -0
  148. package/src/Screens/Debug/MRZTestScreen.tsx +107 -13
  149. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  150. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +58 -35
  151. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +27 -4
  152. package/src/Screens/Dynamic/IdentityDocumentScanningScreen.tsx +6 -0
  153. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +156 -27
  154. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  155. package/src/Screens/Dynamic/VideoCallScreen.tsx +766 -0
  156. package/src/Screens/Static/OTPVerificationScreen.tsx +6 -0
  157. package/src/Screens/Static/QrCodeScanningScreen.tsx +7 -1
  158. package/src/Screens/Static/ResultScreen.tsx +235 -48
  159. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +67 -72
  160. package/src/Shared/Animations/recording.json +1 -0
  161. package/src/Shared/Animations/video-call.json +1 -0
  162. package/src/Shared/Components/DebugNavigationPanel.tsx +252 -51
  163. package/src/Shared/Components/EIDScanner.tsx +223 -116
  164. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  165. package/src/Shared/Components/IdentityDocumentCamera.tsx +224 -188
  166. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  167. package/src/Shared/Components/NavigationManager.tsx +41 -19
  168. package/src/Shared/Contexts/AppContext.ts +2 -0
  169. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  170. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  171. package/src/Shared/EIDReader/bacKey.ts +24 -8
  172. package/src/Shared/EIDReader/eidReader.ts +398 -12
  173. package/src/Shared/EIDReader/eidService.ts +49 -1
  174. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  175. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  176. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  177. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  178. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  179. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  180. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  181. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  182. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  183. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  184. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  185. package/src/Shared/Libs/SignalingClient.ts +189 -0
  186. package/src/Shared/Libs/analytics.utils.ts +8 -0
  187. package/src/Shared/Libs/contains.ts +0 -53
  188. package/src/Shared/Libs/country-display.utils.ts +55 -0
  189. package/src/Shared/Libs/crypto.utils.ts +2 -2
  190. package/src/Shared/Libs/deeplink.utils.ts +12 -1
  191. package/src/Shared/Libs/demo.utils.ts +10 -0
  192. package/src/Shared/Libs/http-client.ts +19 -1
  193. package/src/Shared/Libs/mrz.utils.ts +3 -2
  194. package/src/Shared/Libs/promise.utils.ts +16 -2
  195. package/src/Shared/Libs/status-bar.utils.ts +21 -0
  196. package/src/Shared/Services/DataUploadService.ts +395 -0
  197. package/src/Shared/Services/VideoSessionService.ts +190 -0
  198. package/src/Shared/Services/WebRTCService.ts +636 -0
  199. package/src/Shared/Types/analytics.types.ts +4 -0
  200. package/src/Shared/Types/identificationInfo.ts +16 -1
  201. package/src/Translation/Resources/en.ts +88 -3
  202. package/src/Translation/Resources/tr.ts +89 -3
  203. package/src/Trustchex.tsx +65 -19
  204. package/src/version.ts +1 -1
@@ -0,0 +1,655 @@
1
+ "use strict";
2
+
3
+ import { AESSecureMessagingWrapper } from "../aesSecureMessagingWrapper.js";
4
+ import { TripleDesSecureMessagingWrapper } from "../tripleDesSecureMessagingWrapper.js";
5
+ import { PACEInfo } from "../paceInfo.js";
6
+ import { PACEResult } from "./paceResult.js";
7
+ import { PACEKeySpec } from "../paceKeySpec.js";
8
+ import { EID_CONSTANTS } from "../constants/eidConstants.js";
9
+ import { aesDecryptCBC, aesEncryptCBC, aesCMAC, deriveKey } from "../utils/aesCrypto.utils.js";
10
+ import cryptoUtils from "../utils/crypto.utils.js";
11
+ import TLVUtil from "../tlv/tlv.utils.js";
12
+ import { Buffer } from 'buffer';
13
+ import { ec as EC } from 'elliptic';
14
+
15
+ // Register brainpool curves in elliptic's curve registry (RFC 5639).
16
+ // These are not built-in but are required by most EU ePassports (parameterId 13 = brainpoolP256r1).
17
+ (function registerBrainpoolCurves() {
18
+ const _elliptic = require('elliptic');
19
+ const _hash = require('hash.js');
20
+ const PresetCurve = _elliptic.curves.PresetCurve;
21
+ if (!_elliptic.curves.brainpoolP256r1) {
22
+ _elliptic.curves.brainpoolP256r1 = new PresetCurve({
23
+ type: 'short',
24
+ prime: null,
25
+ p: 'a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377',
26
+ a: '7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9',
27
+ b: '26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6',
28
+ n: 'a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7',
29
+ hash: _hash.sha256,
30
+ gRed: false,
31
+ g: ['8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262', '547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997']
32
+ });
33
+ }
34
+ if (!_elliptic.curves.brainpoolP384r1) {
35
+ _elliptic.curves.brainpoolP384r1 = new PresetCurve({
36
+ type: 'short',
37
+ prime: null,
38
+ p: '8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53',
39
+ a: '7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826',
40
+ b: '04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c11',
41
+ n: '8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046565',
42
+ hash: _hash.sha384,
43
+ gRed: false,
44
+ g: ['1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1e', '8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c5315']
45
+ });
46
+ }
47
+ if (!_elliptic.curves.brainpoolP512r1) {
48
+ _elliptic.curves.brainpoolP512r1 = new PresetCurve({
49
+ type: 'short',
50
+ prime: null,
51
+ p: 'aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca703308717d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3',
52
+ a: '7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca',
53
+ b: '3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723',
54
+ n: 'aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069',
55
+ hash: _hash.sha512,
56
+ gRed: false,
57
+ g: ['81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098eff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822', '7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892']
58
+ });
59
+ }
60
+ })();
61
+ const ENC_MODE = 1;
62
+ const MAC_MODE = 2;
63
+ const PACE_MODE = 3;
64
+
65
+ /**
66
+ * Implements the PACE (Password Authenticated Connection Establishment) protocol.
67
+ *
68
+ * Supports Generic Mapping (GM) with ECDH, as used by modern ePassports
69
+ * per ICAO Doc 9303 Part 11 and BSI TR-03110.
70
+ */
71
+ export class PACEProtocol {
72
+ constructor(service, wrapper, maxTransceiveLengthForProtocol, maxTransceiveLengthForSecureMessaging, shouldCheckMAC) {
73
+ this.service = service;
74
+ this.wrapper = wrapper;
75
+ this.maxTransceiveLengthForProtocol = maxTransceiveLengthForProtocol;
76
+ this.maxTransceiveLengthForSecureMessaging = maxTransceiveLengthForSecureMessaging;
77
+ this.shouldCheckMAC = shouldCheckMAC;
78
+ }
79
+
80
+ /**
81
+ * Performs the full PACE protocol.
82
+ *
83
+ * @param accessKey the access key (MRZ or CAN based)
84
+ * @param oid the PACE OID from EF.CardAccess
85
+ * @param parameterId the standard domain parameter ID (e.g., 13 for brainpoolP256r1)
86
+ */
87
+ async doPACE(accessKey, oid, parameterId, progressCallback) {
88
+ const mappingType = PACEInfo.toMappingType(oid);
89
+ const agreementAlg = PACEInfo.toKeyAgreementAlgorithm(oid);
90
+ const cipherAlg = PACEInfo.toCipherAlgorithm(oid);
91
+ const digestAlg = PACEInfo.toDigestAlgorithm(oid);
92
+ const keyLength = PACEInfo.toKeyLength(oid);
93
+ if (agreementAlg !== 'ECDH') {
94
+ throw new Error(`Only ECDH key agreement is supported, found: ${agreementAlg}`);
95
+ }
96
+ if (mappingType !== 'GM' && mappingType !== 'IM') {
97
+ throw new Error(`Unsupported PACE mapping type: ${mappingType}`);
98
+ }
99
+
100
+ // Derive static PACE key K_pi from the access key
101
+ const staticPACEKeyHex = PACEProtocol.deriveStaticPACEKey(accessKey, cipherAlg, keyLength, digestAlg);
102
+
103
+ // Determine key reference
104
+ let paceKeyReference = EID_CONSTANTS.MRZ_PACE_KEY_REFERENCE;
105
+ if (accessKey instanceof PACEKeySpec) {
106
+ paceKeyReference = accessKey.getKeyReference();
107
+ }
108
+ const refPrivate = parameterId != null ? PACEProtocol.i2os(parameterId) : null;
109
+
110
+ // Pre-initialize curve and generate mapping key pair BEFORE any NFC I/O.
111
+ // brainpoolP512r1 curve init + key gen can take several seconds in JS,
112
+ // which would cause the ISO 14443-4 NFC link to time out if done between steps.
113
+ const curveName = PACEProtocol.getCurveName(parameterId ?? 13);
114
+ console.debug(`[PACE] Starting with OID=${oid}, parameterId=${parameterId}, ` + `curve=${curveName}, ` + `cipher=${cipherAlg}, keyLen=${keyLength}, mapping=${mappingType}`);
115
+ console.debug('[PACE] Pre-initializing curve and generating mapping key pair...');
116
+ const curve = new EC(curveName);
117
+ const mappingKeyPair = curve.genKeyPair();
118
+ console.debug('[PACE] Curve and mapping key pair ready');
119
+ if (progressCallback) {
120
+ progressCallback(5);
121
+ }
122
+
123
+ // Step 0: MSE:Set AT
124
+ console.debug('[PACE] Step 0: MSE:Set AT');
125
+ await this.service.sendMSESetATMutualAuth(this.wrapper, oid, paceKeyReference, refPrivate);
126
+ console.debug('[PACE] Step 0: OK');
127
+ if (progressCallback) {
128
+ progressCallback(6);
129
+ }
130
+
131
+ // Step 1: Encrypted Nonce
132
+ console.debug('[PACE] Step 1: Encrypted Nonce');
133
+ const piccNonce = await this.doPACEStep1(staticPACEKeyHex, cipherAlg, keyLength);
134
+ console.debug(`[PACE] Step 1: OK, nonce length=${piccNonce.length / 2} bytes`);
135
+ if (progressCallback) {
136
+ progressCallback(7);
137
+ }
138
+
139
+ // Step 2: Map Nonce (GM or IM with ECDH)
140
+ let mappingResult;
141
+ console.debug(`[PACE] Step 2: Map Nonce (${mappingType})`);
142
+ if (mappingType === 'IM') {
143
+ mappingResult = await this.doPACEStep2IM(curveName, piccNonce, cipherAlg);
144
+ } else {
145
+ mappingResult = await this.doPACEStep2GM(curveName, piccNonce, mappingKeyPair);
146
+ }
147
+ console.debug(`[PACE] Step 2: OK, ephGen.x=${mappingResult.ephemeralParams.generatorX.substring(0, 16)}...`);
148
+
149
+ // Step 3: Key Agreement
150
+ console.debug('[PACE] Step 3: Key Agreement');
151
+ const {
152
+ pcdKeyPair,
153
+ piccPublicKey,
154
+ sharedSecret
155
+ } = await this.doPACEStep3(curveName, mappingResult.ephemeralParams);
156
+ console.debug(`[PACE] Step 3: OK, sharedSecret=${sharedSecret.substring(0, 16)}...`);
157
+
158
+ // Derive session keys
159
+ const encKeyHex = deriveKey(sharedSecret, cipherAlg, keyLength, ENC_MODE);
160
+ const macKeyHex = deriveKey(sharedSecret, cipherAlg, keyLength, MAC_MODE);
161
+ if (progressCallback) {
162
+ progressCallback(8);
163
+ }
164
+
165
+ // Step 4: Mutual Authentication
166
+ console.debug('[PACE] Step 4: Mutual Authentication');
167
+ await this.doPACEStep4(oid, pcdKeyPair.publicKeyBytes, piccPublicKey, macKeyHex, cipherAlg, keyLength);
168
+ console.debug('[PACE] Step 4: OK - PACE completed successfully');
169
+
170
+ // Create secure messaging wrapper
171
+ let newWrapper;
172
+ const ssc = this.wrapper == null ? 0n : this.wrapper.getSendSequenceCounter();
173
+ if (cipherAlg === 'AES') {
174
+ newWrapper = new AESSecureMessagingWrapper(encKeyHex, macKeyHex, this.maxTransceiveLengthForSecureMessaging, this.shouldCheckMAC, ssc);
175
+ } else {
176
+ newWrapper = new TripleDesSecureMessagingWrapper(encKeyHex, macKeyHex, this.maxTransceiveLengthForSecureMessaging, this.shouldCheckMAC, 0n);
177
+ }
178
+ this.wrapper = newWrapper;
179
+ return new PACEResult(accessKey, mappingType, agreementAlg, cipherAlg, digestAlg, keyLength, newWrapper);
180
+ }
181
+
182
+ /**
183
+ * Step 1: Receive encrypted nonce from PICC, decrypt it.
184
+ */
185
+ async doPACEStep1(staticPACEKeyHex, cipherAlg, _keyLength) {
186
+ // Send empty General Authenticate to receive encrypted nonce
187
+ const step1Response = await this.service.sendGeneralAuthenticate(this.wrapper, [], 256, false);
188
+
189
+ // Unwrap 0x80 tag to get encrypted nonce
190
+ const encryptedNonce = await TLVUtil.unwrapDO(0x80, step1Response);
191
+ const encryptedNonceHex = Buffer.from(encryptedNonce).toString('hex');
192
+
193
+ // Decrypt nonce using static PACE key
194
+ const zeroIV = cipherAlg === 'AES' ? '00000000000000000000000000000000' : '0000000000000000';
195
+ let piccNonce;
196
+ if (cipherAlg === 'AES') {
197
+ piccNonce = aesDecryptCBC(encryptedNonceHex, staticPACEKeyHex, zeroIV);
198
+ } else {
199
+ piccNonce = cryptoUtils.decryptWith3DES(encryptedNonceHex, staticPACEKeyHex);
200
+ }
201
+ return piccNonce;
202
+ }
203
+
204
+ /**
205
+ * Step 2: Generic Mapping with ECDH.
206
+ * Maps the PICC nonce to ephemeral domain parameters.
207
+ */
208
+ async doPACEStep2GM(curveName, piccNonceHex, preGeneratedKeyPair) {
209
+ const curve = new EC(curveName);
210
+
211
+ // Use pre-generated mapping key pair to avoid NFC timeout
212
+ const mappingKeyPair = preGeneratedKeyPair;
213
+ const mappingPublicKey = mappingKeyPair.getPublic();
214
+
215
+ // Encode PCD mapping public key (uncompressed: 0x04 || x || y)
216
+ const pcdMappingPublicKeyBytes = PACEProtocol.encodeECPublicKey(mappingPublicKey.getX().toString(16), mappingPublicKey.getY().toString(16), curve);
217
+
218
+ // Send mapping data (tag 0x81)
219
+ const step2Data = Array.from(TLVUtil.wrapDO(0x81, Array.from(pcdMappingPublicKeyBytes)));
220
+ const le = step2Data.length > 233 ? EID_CONSTANTS.EXTENDED_MAX_TRANSCEIVE_LENGTH : this.maxTransceiveLengthForProtocol;
221
+ const step2Response = await this.service.sendGeneralAuthenticate(this.wrapper, step2Data, le, false);
222
+
223
+ // Unwrap 0x82 tag to get PICC mapping public key
224
+ const piccMappingPublicKeyBytes = await TLVUtil.unwrapDO(0x82, step2Response);
225
+
226
+ // Decode PICC mapping public key
227
+ const piccMappingPublicKey = curve.keyFromPublic(Buffer.from(piccMappingPublicKeyBytes));
228
+
229
+ // Get the full point H from the key agreement
230
+ const H = piccMappingPublicKey.getPublic().mul(mappingKeyPair.getPrivate());
231
+
232
+ // Map nonce: G~ = [s]G + H
233
+ const s = Buffer.from(piccNonceHex, 'hex');
234
+ const sBN = PACEProtocol.bufferToBN(s, curve);
235
+ const G = curve.g;
236
+ const sG = G.mul(sBN);
237
+ const ephemeralGenerator = sG.add(H);
238
+ return {
239
+ ephemeralParams: {
240
+ generatorX: ephemeralGenerator.getX().toString(16),
241
+ generatorY: ephemeralGenerator.getY().toString(16),
242
+ curve: curveName
243
+ }
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Step 2 (IM): Integrated Mapping with ECDH.
249
+ * PCD sends a random nonce T to the PICC; both sides independently compute
250
+ * the ephemeral generator via R_p(s, t) and Icart point encoding.
251
+ * Reference: BSI TR-03110 Part 3, Section 3.3.2 and ICAO SAC TR 2010 Section 4.4.3.3.
252
+ */
253
+ async doPACEStep2IM(curveName, piccNonceHex, cipherAlg) {
254
+ if (cipherAlg !== 'AES') {
255
+ throw new Error(`PACE IM: Only AES cipher is supported in this implementation, found: ${cipherAlg}`);
256
+ }
257
+ const curve = new EC(curveName);
258
+
259
+ // Generate random PCD nonce T with same byte length as PICC nonce s
260
+ const piccNonceBytes = Buffer.from(piccNonceHex, 'hex');
261
+ const pcdNonceHex = cryptoUtils.getRandomValues(piccNonceBytes.length);
262
+
263
+ // Send PCD nonce T in DO 0x81 to PICC via General Authenticate
264
+ // The PICC response (DO 0x82) is empty per TR-SAC 3.3.2 and is ignored
265
+ const step2Data = Array.from(TLVUtil.wrapDO(0x81, Array.from(Buffer.from(pcdNonceHex, 'hex'))));
266
+ const le = step2Data.length > 233 ? EID_CONSTANTS.EXTENDED_MAX_TRANSCEIVE_LENGTH : this.maxTransceiveLengthForProtocol;
267
+ await this.service.sendGeneralAuthenticate(this.wrapper, step2Data, le, false);
268
+
269
+ // Compute t = R_p(s, T) via pseudo-random function
270
+ const p = BigInt('0x' + curve.curve.p.toString(16));
271
+ const tHex = PACEProtocol.pseudoRandomFunction(piccNonceHex, pcdNonceHex, p, cipherAlg);
272
+
273
+ // Map t to an elliptic curve point (new ephemeral generator) via Icart encoding
274
+ const {
275
+ x: generatorX,
276
+ y: generatorY
277
+ } = PACEProtocol.icartPointEncode(tHex, curve);
278
+ return {
279
+ ephemeralParams: {
280
+ generatorX,
281
+ generatorY,
282
+ curve: curveName
283
+ }
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Step 3: Key Agreement.
289
+ * Generate ephemeral key pair, exchange public keys, compute shared secret.
290
+ */
291
+ async doPACEStep3(curveName, ephemeralParams) {
292
+ const curve = new EC(curveName);
293
+
294
+ // Generate ephemeral key pair on the curve with the new generator
295
+ // We need to use the ephemeral generator, but elliptic library
296
+ // works with the original curve generator.
297
+ // Generate a random scalar and compute public key as scalar * ephemeralGenerator
298
+ const privateKey = curve.genKeyPair().getPrivate();
299
+ const ephGen = curve.curve.point(ephemeralParams.generatorX, ephemeralParams.generatorY);
300
+ const pcdPublicPoint = ephGen.mul(privateKey);
301
+
302
+ // Encode PCD ephemeral public key
303
+ const pcdPublicKeyBytes = PACEProtocol.encodeECPoint(pcdPublicPoint.getX().toString(16), pcdPublicPoint.getY().toString(16), curve);
304
+
305
+ // Send public key (tag 0x83)
306
+ const step3Data = Array.from(TLVUtil.wrapDO(0x83, Array.from(pcdPublicKeyBytes)));
307
+ const le = step3Data.length > 233 ? EID_CONSTANTS.EXTENDED_MAX_TRANSCEIVE_LENGTH : this.maxTransceiveLengthForProtocol;
308
+ const step3Response = await this.service.sendGeneralAuthenticate(this.wrapper, step3Data, le, false);
309
+
310
+ // Unwrap 0x84 tag to get PICC ephemeral public key
311
+ const piccPublicKeyBytes = await TLVUtil.unwrapDO(0x84, step3Response);
312
+
313
+ // Decode PICC public key
314
+ const piccPublicPoint = curve.curve.decodePoint(Buffer.from(piccPublicKeyBytes));
315
+
316
+ // Check PCD and PICC public keys differ
317
+ if (pcdPublicPoint.getX().cmp(piccPublicPoint.getX()) === 0 && pcdPublicPoint.getY().cmp(piccPublicPoint.getY()) === 0) {
318
+ throw new Error('PCD and PICC public keys are the same');
319
+ }
320
+
321
+ // Key agreement: K = [SK_PCD] * PK_PICC
322
+ const sharedSecretPoint = piccPublicPoint.mul(privateKey);
323
+ const sharedSecretX = sharedSecretPoint.getX().toString(16);
324
+
325
+ // Pad to full field size
326
+ const fieldSize = curve.curve.p.byteLength() * 2;
327
+ const sharedSecret = sharedSecretX.padStart(fieldSize, '0');
328
+ return {
329
+ pcdKeyPair: {
330
+ publicKeyBytes: pcdPublicKeyBytes,
331
+ privateKey
332
+ },
333
+ piccPublicKey: Uint8Array.from(piccPublicKeyBytes),
334
+ sharedSecret
335
+ };
336
+ }
337
+
338
+ /**
339
+ * Step 4: Mutual Authentication.
340
+ * Compute and exchange authentication tokens.
341
+ */
342
+ async doPACEStep4(oid, pcdPublicKeyBytes, piccPublicKeyBytes, macKeyHex, cipherAlg, _keyLength) {
343
+ // Compute PCD authentication token: T_PCD = MAC(K_mac, PK_PICC~)
344
+ const authInput = PACEProtocol.buildAuthenticationTokenInput(oid, piccPublicKeyBytes);
345
+ const pcdToken = PACEProtocol.computeAuthenticationToken(authInput, macKeyHex, cipherAlg);
346
+
347
+ // Send authentication token (tag 0x85)
348
+ const step4Data = Array.from(TLVUtil.wrapDO(0x85, Array.from(Buffer.from(pcdToken, 'hex'))));
349
+ const step4Response = await this.service.sendGeneralAuthenticate(this.wrapper, step4Data, 256, true);
350
+
351
+ // Unwrap 0x86 tag to get PICC authentication token
352
+ const piccTokenBytes = await TLVUtil.unwrapDO(0x86, step4Response);
353
+
354
+ // Compute expected PICC token: T_PICC = MAC(K_mac, PK_PCD~)
355
+ const expectedAuthInput = PACEProtocol.buildAuthenticationTokenInput(oid, pcdPublicKeyBytes);
356
+ const expectedPICCToken = PACEProtocol.computeAuthenticationToken(expectedAuthInput, macKeyHex, cipherAlg);
357
+
358
+ // Verify
359
+ const expectedBytes = Buffer.from(expectedPICCToken, 'hex');
360
+ const receivedBytes = Buffer.from(piccTokenBytes);
361
+ if (Buffer.compare(expectedBytes, receivedBytes) !== 0) {
362
+ throw new Error('PICC authentication token mismatch');
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Build the input for the authentication token MAC.
368
+ * Per BSI TR-03110 Part 3 Section 4.5.3, the authentication token is computed
369
+ * over a public key data object wrapped in tag 0x7F49.
370
+ */
371
+ static buildAuthenticationTokenInput(oid, publicKeyBytes) {
372
+ // The authentication token input is:
373
+ // 0x7F49 || len || 0x06 || OID_len || OID_value || 0x86 || pubkey_len || pubkey_value
374
+ const oidComponents = oid.split('.').map(Number);
375
+ const oidEncoded = PACEProtocol.encodeOIDValue(oidComponents);
376
+ const oidTLV = [0x06, oidEncoded.length, ...oidEncoded];
377
+ const pubKeyTLV = [0x86, ...PACEProtocol.encodeLengthBytes(publicKeyBytes.length), ...publicKeyBytes];
378
+ const innerData = [...oidTLV, ...pubKeyTLV];
379
+ // Wrap in 0x7F49 tag (two-byte tag)
380
+ const wrapped = [0x7f, 0x49, ...PACEProtocol.encodeLengthBytes(innerData.length), ...innerData];
381
+ return Buffer.from(wrapped).toString('hex');
382
+ }
383
+ static encodeLengthBytes(length) {
384
+ if (length < 0x80) {
385
+ return [length];
386
+ } else if (length < 0x100) {
387
+ return [0x81, length];
388
+ } else {
389
+ return [0x82, length >> 8 & 0xff, length & 0xff];
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Compute authentication token using AES-CMAC or DES MAC.
395
+ */
396
+ static computeAuthenticationToken(dataHex, macKeyHex, cipherAlg) {
397
+ if (cipherAlg === 'AES') {
398
+ const mac = aesCMAC(dataHex, macKeyHex);
399
+ // Truncate to 8 bytes for authentication token
400
+ return mac.substring(0, 16);
401
+ } else {
402
+ return cryptoUtils.computeMac(dataHex, macKeyHex, true);
403
+ }
404
+ }
405
+
406
+ /**
407
+ * Derive the static PACE key K_pi from the access key.
408
+ */
409
+ static deriveStaticPACEKey(accessKey, cipherAlg, keyLength, _digestAlg) {
410
+ let keySeed;
411
+ if ('getDocumentNumber' in accessKey && typeof accessKey.getDocumentNumber === 'function') {
412
+ // BAC key spec - use MRZ-derived key seed
413
+ keySeed = accessKey.getKey();
414
+ } else if (accessKey instanceof PACEKeySpec) {
415
+ keySeed = accessKey.getKey();
416
+ } else {
417
+ keySeed = accessKey.getKey();
418
+ }
419
+ return deriveKey(keySeed, cipherAlg, keyLength, PACE_MODE);
420
+ }
421
+
422
+ // --- EC Utility Methods ---
423
+
424
+ static encodeECPublicKey(xHex, yHex, curve) {
425
+ return PACEProtocol.encodeECPoint(xHex, yHex, curve);
426
+ }
427
+ static encodeECPoint(xHex, yHex, curve) {
428
+ const fieldSize = curve.curve.p.byteLength();
429
+ const x = xHex.padStart(fieldSize * 2, '0');
430
+ const y = yHex.padStart(fieldSize * 2, '0');
431
+ const uncompressed = '04' + x + y;
432
+ return Uint8Array.from(Buffer.from(uncompressed, 'hex'));
433
+ }
434
+ static bufferToBN(buf, curve) {
435
+ // Convert buffer to BN used by elliptic library
436
+ const hex = buf.toString('hex');
437
+ return curve.keyFromPrivate(hex).getPrivate();
438
+ }
439
+ static encodeOIDValue(components) {
440
+ if (components.length < 2) {
441
+ throw new Error('OID must have at least 2 components');
442
+ }
443
+ const encoded = [];
444
+ encoded.push(components[0] * 40 + components[1]);
445
+ for (let i = 2; i < components.length; i++) {
446
+ const value = components[i];
447
+ if (value < 128) {
448
+ encoded.push(value);
449
+ } else {
450
+ const bytes = [];
451
+ let v = value;
452
+ bytes.push(v & 0x7f);
453
+ v >>= 7;
454
+ while (v > 0) {
455
+ bytes.push(v & 0x7f | 0x80);
456
+ v >>= 7;
457
+ }
458
+ bytes.reverse();
459
+ encoded.push(...bytes);
460
+ }
461
+ }
462
+ return encoded;
463
+ }
464
+
465
+ // ---- PACE IM helpers ----
466
+
467
+ /**
468
+ * Fast modular exponentiation using BigInt (square-and-multiply).
469
+ */
470
+ static modPow(base, exp, mod) {
471
+ if (mod === 1n) return 0n;
472
+ let result = 1n;
473
+ base = (base % mod + mod) % mod;
474
+ while (exp > 0n) {
475
+ if (exp & 1n) {
476
+ result = result * base % mod;
477
+ }
478
+ exp >>= 1n;
479
+ base = base * base % mod;
480
+ }
481
+ return result;
482
+ }
483
+
484
+ /**
485
+ * Pseudo-random function R_p(s, t) for PACE Integrated Mapping.
486
+ * Specified in ICAO Doc 9303 Part 11, Section 4.4.3.3.2 and BSI TR-03110.
487
+ *
488
+ * Uses the block cipher in CBC mode (IV=0) to derive a field element mod p.
489
+ *
490
+ * @param sHex - PICC nonce s (hex)
491
+ * @param tHex - PCD nonce t (hex, same length as s)
492
+ * @param p - prime of the field GF(p)
493
+ * @param cipherAlg - 'AES'
494
+ * @returns field element as hex string (big-endian, same byte length as s)
495
+ */
496
+ static pseudoRandomFunction(sHex, tHex, p, cipherAlg) {
497
+ if (cipherAlg !== 'AES') {
498
+ throw new Error(`PACE IM pseudoRandomFunction: unsupported cipher ${cipherAlg}`);
499
+ }
500
+ const l = sHex.length / 2 * 8; // bit length of s
501
+
502
+ // Constants from ICAO Doc 9303 Part 11, Table 4 (also BSI TR-03110)
503
+ let c0Hex;
504
+ let c1Hex;
505
+ if (l === 128) {
506
+ c0Hex = 'a668892a7c41e3ca739f40b057d85904';
507
+ c1Hex = 'a4e136ac725f738b01c1f60217c188ad';
508
+ } else if (l === 192 || l === 256) {
509
+ c0Hex = 'd463d65234124ef7897054986dca0a174e28df758cbaa03f240616414d5a1676';
510
+ c1Hex = '54bd7255f0aaf831bec3423fcf39d69b6cbf066677d0faae5aadd99df8e53517';
511
+ } else {
512
+ throw new Error(`PACE IM pseudoRandomFunction: unsupported nonce length ${l} bits`);
513
+ }
514
+ const zeroIV = '00000000000000000000000000000000'; // 16-byte zero IV
515
+
516
+ // Initial key: key_0 = E_T(S) — encrypt S with key T, AES-CBC, IV=0
517
+ let keyHex = aesEncryptCBC(sHex, tHex, zeroIV);
518
+
519
+ // Generate output blocks: for each i, key_{i+1} = E_key_i(c0), x_i = E_key_i(c1)
520
+ // Repeat until n blocks of l bits cover p.bitLength + 64 bits
521
+ const pBitLength = p.toString(2).length;
522
+ const outputBlocks = [];
523
+ let n = 0;
524
+ while (n * l < pBitLength + 64) {
525
+ const newKeyHex = aesEncryptCBC(c0Hex, keyHex, zeroIV);
526
+ const xiHex = aesEncryptCBC(c1Hex, keyHex, zeroIV);
527
+ keyHex = newKeyHex;
528
+ outputBlocks.push(xiHex);
529
+ n++;
530
+ }
531
+
532
+ // x = (x_1 || x_2 || ... || x_n) mod p, returned as field-element-sized hex
533
+ const xBigInt = BigInt('0x' + outputBlocks.join(''));
534
+ const result = xBigInt % p;
535
+ const fieldBytes = sHex.length / 2;
536
+ return result.toString(16).padStart(fieldBytes * 2, '0');
537
+ }
538
+
539
+ /**
540
+ * Icart's deterministic encoding of a field element to a curve point.
541
+ * Maps an element t ∈ GF(p) to a point (x, y) on y² = x³ + ax + b.
542
+ * Requires p ≡ 3 (mod 4).
543
+ * Reference: ICAO SAC TR 2010, Section 5.2.
544
+ *
545
+ * @param tHex - field element as hex string
546
+ * @param curve - the elliptic curve
547
+ * @returns { x, y } as hex strings (field-element-width, big-endian)
548
+ */
549
+ static icartPointEncode(tHex, curve) {
550
+ const p = BigInt('0x' + curve.curve.p.toString(16));
551
+ // curve.curve.a and .b are stored in Montgomery (red) form in elliptic —
552
+ // must call fromRed() to get the actual field element values.
553
+ const a = BigInt('0x' + curve.curve.a.fromRed().toString(16));
554
+ const b = BigInt('0x' + curve.curve.b.fromRed().toString(16));
555
+ if (p % 4n !== 3n) {
556
+ throw new Error('PACE IM Icart encoding requires p ≡ 3 (mod 4)');
557
+ }
558
+ const t = BigInt('0x' + tHex);
559
+ // Helper: reduce x into [0, p) handling negative intermediate values
560
+ const mod = x => (x % p + p) % p;
561
+
562
+ // 1. alpha = -t² mod p
563
+ const alpha = mod(-(t * t % p));
564
+
565
+ // 2. x2 = -b * (1 + alpha + alpha²) / (a * (alpha + alpha²)) mod p
566
+ const alphaSq = alpha * alpha % p;
567
+ const alphaPlusAlphaSq = (alpha + alphaSq) % p;
568
+ const onePlusAlphaPlusAlphaSq = (1n + alphaPlusAlphaSq) % p;
569
+ const aTimesAlphaPlusAlphaSq = a * alphaPlusAlphaSq % p;
570
+ // Modular inverse via Fermat's little theorem: a^(p-2) mod p
571
+ const inv = PACEProtocol.modPow(aTimesAlphaPlusAlphaSq, p - 2n, p);
572
+ const x2 = mod(-(b * onePlusAlphaPlusAlphaSq % p) * inv % p);
573
+
574
+ // 3. x3 = alpha * x2 mod p
575
+ const x3 = alpha * x2 % p;
576
+
577
+ // 4. h2 = x2³ + a*x2 + b mod p
578
+ const h2 = mod(x2 * x2 % p * x2 % p + a * x2 % p + b);
579
+
580
+ // 5. u = t³ * h2 mod p
581
+ const u = t * t % p * t % p * h2 % p;
582
+
583
+ // 6. aa = h2^(p-1-(p+1)/4) mod p (related to square root formula for p ≡ 3 mod 4)
584
+ const ppo4 = (p + 1n) / 4n;
585
+ const aa = PACEProtocol.modPow(h2, p - 1n - ppo4, p);
586
+
587
+ // 7. Check if h2 is a quadratic residue (aa² * h2 == 1), choose (x,y) accordingly
588
+ const aaSqTimesH2 = PACEProtocol.modPow(aa, 2n, p) * h2 % p;
589
+ let resX;
590
+ let resY;
591
+ if (aaSqTimesH2 === 1n) {
592
+ resX = x2;
593
+ resY = aa * h2 % p;
594
+ } else {
595
+ resX = x3;
596
+ resY = aa * u % p;
597
+ }
598
+
599
+ // All PACE curves (NIST P-*, brainpool) have cofactor = 1, no cofactor multiplication needed
600
+ const fieldHexLen = Math.ceil(p.toString(16).length / 2) * 2;
601
+ return {
602
+ x: resX.toString(16).padStart(fieldHexLen, '0'),
603
+ y: resY.toString(16).padStart(fieldHexLen, '0')
604
+ };
605
+ }
606
+ static i2os(value) {
607
+ if (value === 0) return [0];
608
+ const bytes = [];
609
+ let v = value;
610
+ while (v > 0) {
611
+ bytes.unshift(v & 0xff);
612
+ v >>= 8;
613
+ }
614
+ return bytes;
615
+ }
616
+
617
+ /**
618
+ * Map standard domain parameter ID to elliptic curve name.
619
+ */
620
+ static getCurveName(parameterId) {
621
+ // BSI TR-03110 Table D.2 / ICAO Doc 9303 standardized domain parameters
622
+ switch (parameterId) {
623
+ case 8:
624
+ return 'p192';
625
+ // NIST P-192
626
+ case 9:
627
+ return 'brainpoolP192r1';
628
+ case 10:
629
+ return 'p224';
630
+ // NIST P-224
631
+ case 11:
632
+ return 'brainpoolP224r1';
633
+ case 12:
634
+ return 'p256';
635
+ // NIST P-256
636
+ case 13:
637
+ return 'brainpoolP256r1';
638
+ // Most common in EU passports
639
+ case 14:
640
+ return 'brainpoolP320r1';
641
+ case 15:
642
+ return 'p384';
643
+ // NIST P-384
644
+ case 16:
645
+ return 'brainpoolP384r1';
646
+ case 17:
647
+ return 'brainpoolP512r1';
648
+ case 18:
649
+ return 'p521';
650
+ // NIST P-521
651
+ default:
652
+ throw new Error(`Unsupported domain parameter ID: ${parameterId}`);
653
+ }
654
+ }
655
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Result of PACE protocol execution.
5
+ */
6
+ export class PACEResult {
7
+ constructor(paceKey, mappingType, agreementAlg, cipherAlg, digestAlg, keyLength, wrapper) {
8
+ this.paceKey = paceKey;
9
+ this.mappingType = mappingType;
10
+ this.agreementAlg = agreementAlg;
11
+ this.cipherAlg = cipherAlg;
12
+ this.digestAlg = digestAlg;
13
+ this.keyLength = keyLength;
14
+ this.wrapper = wrapper;
15
+ }
16
+ getPACEKey() {
17
+ return this.paceKey;
18
+ }
19
+ getMappingType() {
20
+ return this.mappingType;
21
+ }
22
+ getAgreementAlg() {
23
+ return this.agreementAlg;
24
+ }
25
+ getCipherAlg() {
26
+ return this.cipherAlg;
27
+ }
28
+ getDigestAlg() {
29
+ return this.digestAlg;
30
+ }
31
+ getKeyLength() {
32
+ return this.keyLength;
33
+ }
34
+ getWrapper() {
35
+ return this.wrapper;
36
+ }
37
+ }