diff --git a/app/src/screens/UserInfo.tsx b/app/src/screens/UserInfo.tsx
index 0d7ec86e..1ef646ae 100644
--- a/app/src/screens/UserInfo.tsx
+++ b/app/src/screens/UserInfo.tsx
@@ -2,15 +2,11 @@ import React from 'react';
import { YStack, Text, XStack, Separator } from 'tamagui';
import useUserStore from '../stores/userStore';
import { textBlack, separatorColor } from '../utils/colors';
-import { findSubarrayIndex } from '../../../common/src/utils/utils';
-import { PassportData } from '../../../common/src/utils/types';
-import { hash } from '../../../common/src/utils/utils';
-import { parseCertificate } from '../../../common/src/utils/certificates/handleCertificate';
+import { parsePassportData } from '../utils/parsePassportData';
const UserInfo: React.FC = () => {
const { passportData } = useUserStore();
- const { eContent, signedAttr, dg1Hash, dgPresents } = passportData as PassportData;
- const dg1HashOffset = dg1Hash ? findSubarrayIndex(eContent, dg1Hash.map(byte => byte > 127 ? byte - 256 : byte)) : undefined;
+ const passportMetaData = passportData ? parsePassportData(passportData) : null;
const InfoRow = ({ label, value }: { label: string; value: string | number }) => (
@@ -19,69 +15,33 @@ const UserInfo: React.FC = () => {
);
- function findHashSizeOfEContent(eContent: number[], signedAttr: number[]) {
- const allHashes = ['sha512', 'sha384', 'sha256', 'sha1'];
- for (const hashFunction of allHashes) {
- const hashValue = hash(hashFunction, eContent);
- const hashOffset = findSubarrayIndex(signedAttr, hashValue);
- if (hashOffset !== -1) {
- return { hashFunction, offset: hashOffset };
- }
- }
- }
-
- const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(eContent, signedAttr) || { hashFunction: '', offset: 0 };
- const dscHashFunction = parseCertificate(passportData?.dsc || '').hashFunction;
-
-
-
return (
Passport Data Info
- item.replace('DG', '')).join(',') || 'None'}
- />
+
-
+
-
+
+
-
+
-
+
+
-
+
+
-
+
-
+
+
);
};
diff --git a/app/src/utils/parsePassportData.ts b/app/src/utils/parsePassportData.ts
new file mode 100644
index 00000000..49e444f5
--- /dev/null
+++ b/app/src/utils/parsePassportData.ts
@@ -0,0 +1,83 @@
+import { PassportData } from '../../../common/src/utils/types';
+import { findSubarrayIndex, formatMrz, hash } from '../../../common/src/utils/utils';
+import { parseCertificate } from '../../../common/src/utils/certificates/handleCertificate';
+
+export interface PassportMetadata {
+ dataGroups: string;
+ dg1HashFunction: string;
+ dg1HashOffset: number;
+ eContentSize: number;
+ eContentHashFunction: string;
+ eContentHashOffset: number;
+ signedAttrSize: number;
+ signedAttrHashFunction: string;
+ countryCode?: string;
+}
+
+export function findHashSizeOfEContent(eContent: number[], signedAttr: number[]) {
+ const allHashes = ['sha512', 'sha384', 'sha256', 'sha1'];
+ for (const hashFunction of allHashes) {
+ const hashValue = hash(hashFunction, eContent);
+ const hashOffset = findSubarrayIndex(signedAttr, hashValue);
+ if (hashOffset !== -1) {
+ return { hashFunction, offset: hashOffset };
+ }
+ }
+ return { hashFunction: 'unknown', offset: -1 };
+}
+
+export function findDG1HashInEContent(mrz: string, eContent: number[]): { hash: number[], hashFunction: string } | null {
+ const hashFunctions = ['sha512', 'sha384', 'sha256', 'sha1'];
+ const formattedMrz = formatMrz(mrz);
+
+ for (const hashFunction of hashFunctions) {
+ const hashValue = hash(hashFunction, formattedMrz);
+ const hashOffset = findSubarrayIndex(eContent, hashValue);
+
+ if (hashOffset !== -1) {
+ return { hash: hashValue, hashFunction };
+ }
+ }
+ return null;
+}
+
+export function getCountryCodeFromMrz(mrz: string): string {
+ return mrz.substring(2, 5);
+}
+
+export function parsePassportData(passportData: PassportData): PassportMetadata {
+ // Extract DG1 hash info
+ const dg1HashInfo = passportData.mrz ?
+ findDG1HashInEContent(passportData.mrz, passportData.eContent) :
+ null;
+
+ // Use extracted DG1 hash if found, otherwise use provided dg1Hash
+ const dg1Hash = dg1HashInfo?.hash || passportData.dg1Hash;
+ const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
+
+ const dg1HashOffset = dg1Hash
+ ? findSubarrayIndex(
+ passportData.eContent,
+ dg1Hash.map(byte => byte > 127 ? byte - 256 : byte)
+ )
+ : 0;
+
+ const { hashFunction: eContentHashFunction, offset: eContentHashOffset } =
+ findHashSizeOfEContent(passportData.eContent, passportData.signedAttr);
+
+ const dscHashFunction = passportData.dsc ?
+ parseCertificate(passportData.dsc).hashFunction :
+ 'unknown';
+
+ return {
+ dataGroups: passportData.dgPresents?.toString().split(',').map(item => item.replace('DG', '')).join(',') || 'None',
+ dg1HashFunction,
+ dg1HashOffset,
+ eContentSize: passportData.eContent?.length || 0,
+ eContentHashFunction,
+ eContentHashOffset,
+ signedAttrSize: passportData.signedAttr?.length || 0,
+ signedAttrHashFunction: dscHashFunction,
+ countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : undefined
+ };
+}
diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts
index fdb92983..96582f7e 100644
--- a/common/src/utils/utils.ts
+++ b/common/src/utils/utils.ts
@@ -409,8 +409,23 @@ export function generateMerkleProof(imt: LeanIMT, _index: number, maxDepth: numb
return { merkleProofSiblings, merkleProofIndices, depthForThisOne };
}
-export function findSubarrayIndex(arr: any[], subarray: any[]): number {
- return arr.findIndex((_, index) => subarray.every((element, i) => element === arr[index + i]));
+export function findSubarrayIndex(arr: number[], subArr: number[]): number {
+ if (!arr || !Array.isArray(arr) || !subArr || !Array.isArray(subArr)) {
+ console.warn('Invalid input to findSubarrayIndex:', { arr, subArr });
+ return -1;
+ }
+
+ if (subArr.length === 0) {
+ return -1;
+ }
+
+ if (subArr.length > arr.length) {
+ return -1;
+ }
+
+ return arr.findIndex((_, i) =>
+ subArr.every((val, j) => arr[i + j] === val)
+ );
}
export function extractRSFromSignature(signatureBytes: number[]): { r: string; s: string } {
@@ -479,9 +494,9 @@ function checkStringLength(str: string) {
function stringToBigInt(str: string): bigint {
return BigInt(
'1' +
- Array.from(str)
- .map((char) => char.charCodeAt(0).toString().padStart(3, '0'))
- .join('')
+ Array.from(str)
+ .map((char) => char.charCodeAt(0).toString().padStart(3, '0'))
+ .join('')
);
}
diff --git a/registry/.gitignore b/registry/.gitignore
index 31bdb75a..89c473c8 100644
--- a/registry/.gitignore
+++ b/registry/.gitignore
@@ -1,3 +1,4 @@
.env
.env.local
-outputs/
\ No newline at end of file
+outputs/
+src/passport_data/passport_data/
\ No newline at end of file
diff --git a/registry/src/passport_data/parse_passport_data.ts b/registry/src/passport_data/parse_passport_data.ts
new file mode 100644
index 00000000..795be030
--- /dev/null
+++ b/registry/src/passport_data/parse_passport_data.ts
@@ -0,0 +1,55 @@
+import fs from 'fs';
+import path from 'path';
+import { PassportData } from '../../../common/src/utils/types';
+import { parsePassportData } from '../../../app/src/utils/parsePassportData';
+
+function parsePassportFile(filePath: string) {
+ try {
+ const fileContent = fs.readFileSync(filePath, 'utf8');
+ const passportData = JSON.parse(fileContent) as PassportData;
+
+ const info = parsePassportData(passportData);
+
+ // Print the results
+ console.log(`\nProcessing file: ${path.basename(filePath)}`);
+ console.log('----------------------------------------');
+ if (info.countryCode) console.log(`Country Code: ${info.countryCode}`);
+ console.log(`Data Groups: ${info.dataGroups}`);
+ console.log(`DG1 Hash Function: ${info.dg1HashFunction}`);
+ console.log(`DG1 Hash Offset: ${info.dg1HashOffset}`);
+ console.log(`eContent Size: ${info.eContentSize}`);
+ console.log(`eContent Hash Function: ${info.eContentHashFunction}`);
+ console.log(`eContent Hash Offset: ${info.eContentHashOffset}`);
+ console.log(`Signed Attributes Size: ${info.signedAttrSize}`);
+ console.log(`Signed Attributes Hash Function: ${info.signedAttrHashFunction}`);
+
+ } catch (error) {
+ console.error(`Error processing file ${filePath}:`, error);
+ }
+}
+
+function main() {
+ const directoryPath = path.join(__dirname, 'passport_data');
+ console.log(directoryPath);
+
+ try {
+ const files = fs.readdirSync(directoryPath);
+ const jsonFiles = files.filter(file => file.endsWith('.json'));
+
+ if (jsonFiles.length === 0) {
+ console.log('No JSON files found in the passport_data directory');
+ return;
+ }
+
+ jsonFiles.forEach(file => {
+ const filePath = path.join(directoryPath, file);
+ parsePassportFile(filePath);
+ });
+
+ } catch (error) {
+ console.error('Error reading directory:', error);
+ }
+}
+
+// Execute the script
+main();