simplify PassportData format

This commit is contained in:
0xturboblitz
2023-09-27 18:11:47 +02:00
parent 4d40dd63cd
commit 38034de41f
5 changed files with 41 additions and 73 deletions

View File

@@ -38,7 +38,7 @@ import {computeAndCheckEContent} from './utils/computeEContent';
console.log('DEFAULT_PNUMBER', DEFAULT_PNUMBER);
const CACHE_DATA_IN_LOCAL_SERVER = true;
const SKIP_SCAN = true;
const SKIP_SCAN = false;
function App(): JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
@@ -78,35 +78,26 @@ function App(): JSX.Element {
async function handleResponse(response: any) {
const {
mrzInfo,
publicKey,
publicKeyPEM,
mrz,
modulus,
dataGroupHashes,
eContent,
encryptedDigest,
contentBytes,
eContentDecomposed,
} = response;
const passportData: PassportData = {
mrzInfo: JSON.parse(mrzInfo),
publicKey: publicKey,
publicKeyPEM: publicKeyPEM,
mrz: mrz,
modulus: modulus,
dataGroupHashes: dataHashesObjToArray(JSON.parse(dataGroupHashes)),
eContent: JSON.parse(eContent),
encryptedDigest: JSON.parse(encryptedDigest),
contentBytes: JSON.parse(contentBytes),
eContentDecomposed: JSON.parse(eContentDecomposed),
};
console.log('mrzInfo', passportData.mrzInfo);
console.log('publicKey', passportData.publicKey);
console.log('publicKeyPEM', passportData.publicKeyPEM);
console.log('mrz', passportData.mrz);
console.log('modulus', passportData.modulus);
console.log('dataGroupHashes', passportData.dataGroupHashes);
console.log('eContent', passportData.eContent);
console.log('encryptedDigest', passportData.encryptedDigest);
console.log('contentBytes', passportData.contentBytes);
console.log('eContentDecomposed', passportData.eContentDecomposed);
setPassportData(passportData);
@@ -143,6 +134,7 @@ function App(): JSX.Element {
dateOfBirth: dateOfBirth,
dateOfExpiry: dateOfExpiry,
});
console.log('response', response);
console.log('scanned');
handleResponse(response);
} catch (e) {
@@ -265,7 +257,7 @@ function App(): JSX.Element {
<View style={styles.sectionContainer}>
<Text style={styles.header}>Connection successful</Text>
<Text style={styles.header}>
Hi {getFirstName(passportData?.mrzInfo)} !{' '}
{passportData && `Hi ${getFirstName(passportData.mrz)} ! `}
</Text>
<Text style={styles.header}>Input your address or ens</Text>
<TextInput

View File

@@ -76,6 +76,7 @@ import java.security.cert.X509Certificate
import java.security.spec.MGF1ParameterSpec
import java.security.spec.PSSParameterSpec
import java.text.ParseException
import java.security.interfaces.RSAPublicKey
import java.text.SimpleDateFormat
import java.util.*
import java.security.PublicKey
@@ -505,18 +506,15 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val eContentAsn1InputStream = ASN1InputStream(sodFile.eContent.inputStream())
val eContentDecomposed: ASN1Primitive = eContentAsn1InputStream.readObject()
val rsaPublicKey = sodFile.docSigningCertificate.publicKey as RSAPublicKey
val passport = Arguments.createMap()
passport.putString("mrzInfo", gson.toJson(mrzInfo))
passport.putString("dg2File", gson.toJson(dg2File))
passport.putString("publicKey", sodFile.docSigningCertificate.publicKey.toString())
passport.putString("publicKeyPEM", Base64.encodeToString(sodFile.docSigningCertificate.publicKey.encoded, Base64.DEFAULT))
passport.putString("mrz", mrzInfo.toString())
passport.putString("modulus", rsaPublicKey.modulus.toString())
passport.putString("dataGroupHashes", gson.toJson(sodFile.dataGroupHashes))
passport.putString("eContent", gson.toJson(sodFile.eContent))
passport.putString("encryptedDigest", gson.toJson(sodFile.encryptedDigest))
passport.putString("contentBytes", gson.toJson(signedData.getEncapContentInfo()))
passport.putString("eContentDecomposed", gson.toJson(eContentDecomposed))
// Another way to get signing time is to get into signedData.signerInfos, then search for the ICO identifier 1.2.840.113549.1.9.5
// passport.putString("signerInfos", gson.toJson(signedData.signerInfos))
@@ -524,13 +522,14 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// Log.d(TAG, "signedData.signerInfos: ${gson.toJson(signedData.signerInfos)}")
// Log.d(TAG, "signedData.certificates: ${gson.toJson(signedData.certificates)}")
val base64 = bitmap?.let { toBase64(it, quality) }
val photo = Arguments.createMap()
photo.putString("base64", base64 ?: "")
photo.putInt("width", bitmap?.width ?: 0)
photo.putInt("height", bitmap?.height ?: 0)
passport.putMap("photo", photo)
// val base64 = bitmap?.let { toBase64(it, quality) }
// val photo = Arguments.createMap()
// photo.putString("base64", base64 ?: "")
// photo.putInt("width", bitmap?.width ?: 0)
// photo.putInt("height", bitmap?.height ?: 0)
// passport.putMap("photo", photo)
// passport.putString("dg2File", gson.toJson(dg2File))
scanPromise?.resolve(passport)
resetState()
}

View File

@@ -16,7 +16,7 @@ import {DataHash} from '../types/passportData';
// This script tests the whole flow from MRZ to signature
// The passportData is imported from passportData.json written by the server
const mrz = assembleMrz(passportData.mrzInfo);
const mrz = passportData.mrz;
console.log('mrz: ', mrz);
@@ -26,9 +26,8 @@ const dataHashes = passportData.dataGroupHashes as DataHash[];
const mrzHash = hash(formatMrz(mrz));
console.log('mrzHash:', mrzHash);
console.log('dataHashes[0][1]:', dataHashes[0][1]);
console.log(
'Are they equal ?',
'mrzHash === dataHashes[0][1] ?',
arraysAreEqual(mrzHash, dataHashes[0][1] as number[]),
);
@@ -37,50 +36,31 @@ const concatenatedDataHashes = formatAndConcatenateDataHashes(
dataHashes,
);
console.log('concatenatedDataHashes', concatenatedDataHashes);
console.log(
'passportData.contentBytes.content.string',
passportData.contentBytes.content.string,
);
console.log(
'Are they equal ?',
arraysAreEqual(
concatenatedDataHashes,
passportData.contentBytes.content.string,
),
);
const concatenatedDataHashesHashDigest = hash(concatenatedDataHashes);
const timeOfSignature = findTimeOfSignature(passportData.eContentDecomposed);
// check that concatenatedDataHashesHashDigest is at the right place of passportData.eContent
const sliceOfEContent = passportData.eContent.slice(72, 72 + 32);
const eContent = assembleEContent(
concatenatedDataHashesHashDigest,
timeOfSignature,
);
console.log('eContent reconstructed', eContent);
console.log('passportData.eContent', passportData.eContent);
console.log(
'Are they equal ?',
arraysAreEqual(eContent, passportData.eContent),
arraysAreEqual(sliceOfEContent, concatenatedDataHashesHashDigest),
);
// now let's verify the signature
const {modulus, exponent} = parsePubKeyString(passportData.publicKey);
// const {modulus, exponent} = parsePubKeyString(passportData.publicKey);
// Create the public key
const rsa = forge.pki.rsa;
const publicKey = rsa.setPublicKey(
new forge.jsbn.BigInteger(modulus, 16),
new forge.jsbn.BigInteger(exponent, 16),
new forge.jsbn.BigInteger(passportData.modulus, 10),
new forge.jsbn.BigInteger("10001", 16),
);
// SHA-256 hash of the eContent
const md = forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
md.update(forge.util.binary.raw.encode(new Uint8Array(passportData.eContent)));
const hashOfEContent = md.digest().getBytes();
console.log('modulus', hexToDecimal(modulus));
console.log('modulus', passportData.modulus);
console.log('eContent', bytesToBigDecimal(passportData.eContent));
console.log('signature', bytesToBigDecimal(passportData.encryptedDigest));
// Convert the hash to a single decimal number
@@ -106,7 +86,6 @@ function hash(bytesArray: number[]): number[] {
hash.update(Buffer.from(bytesArray));
return Array.from(hash.digest()).map(x => (x < 128 ? x : x - 256));
}
function bytesToBigDecimal(arr: number[]): string {
let result = BigInt(0);
for (let i = 0; i < arr.length; i++) {

View File

@@ -19,12 +19,9 @@ export type MrzInfo = {
export type DataHash = [number, number[]];
export type PassportData = {
mrzInfo: MrzInfo;
publicKey: any;
publicKeyPEM: string;
mrz: string;
modulus: string;
dataGroupHashes: DataHash[];
eContent: any;
encryptedDigest: any;
contentBytes: any;
eContentDecomposed: any;
eContent: number[];
encryptedDigest: number[];
};

View File

@@ -15,7 +15,8 @@ export function checkInputs(
return true;
}
export function getFirstName(mrzInfo: any): string {
const firstName = mrzInfo.secondaryIdentifier.split('<')[0];
return firstName.charAt(0).toUpperCase() + firstName.slice(1).toLowerCase();
}
export function getFirstName(mrz: string): string {
const names = mrz.split("<<");
const firstName = names[1].split("<")[0].trim();
return firstName || "Unknown";
}