Skip to content

Commit

Permalink
Merge pull request #165 from zk-passport/new-samples
Browse files Browse the repository at this point in the history
New samples
  • Loading branch information
0xturboblitz authored Aug 3, 2024
2 parents 74740fa + 57c40e6 commit f513a43
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/ios/PassportReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class PassportReader: NSObject{
ret["eContentBase64"] = try sod.getEncapsulatedContent().base64EncodedString() // this is what we call concatenatedDataHashes, not the true eContent

ret["signatureAlgorithm"] = try sod.getSignatureAlgorithm()
ret["encapsulatedContentDigestAlgorithm"] = try sod.getEncapsulatedContentDigestAlgorithm()

let messageDigestFromSignedAttributes = try sod.getMessageDigestFromSignedAttributes()
let signedAttributes = try sod.getSignedAttributes()
Expand Down
1 change: 1 addition & 0 deletions app/src/utils/nfcScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const handleResponseIOS = async (
console.log('residenceAddress', parsed.residenceAddress)
console.log('passportPhoto', parsed.passportPhoto.substring(0, 100) + '...')
console.log('signatureAlgorithm', signatureAlgorithm)
console.log('encapsulatedContentDigestAlgorithm', parsed.encapsulatedContentDigestAlgorithm)
console.log('parsed.documentSigningCertificate', parsed.documentSigningCertificate)
const pem = JSON.parse(parsed.documentSigningCertificate).PEM.replace(/\n/g, '');
const certificate = forge.pki.certificateFromPem(pem);
Expand Down
106 changes: 106 additions & 0 deletions common/scripts/passportData/sha256_sha1mrz_rsa_65537.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import assert from "assert";
import { PassportData } from "../../src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../src/utils/utils";
import * as forge from 'node-forge';
import { writeFileSync, readFileSync } from "fs";
import { mock_dsc_key_sha256_rsa_4096 } from "../../src/constants/mockCertificates";

const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
const sampleDataHashes = [
[
2,
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
],
[
3,
[0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82]
],
[
11,
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
],
[
12,
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
],
[
13,
[91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38]
],
[
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
] as [number, number[]][]
const signatureAlgorithm = 'sha256WithRSAEncryption'
const hashLen = 32

export function genMockPassportData_sha256WithRSAEncryption_sha1MRZ_65537(): PassportData {
const mrzHash = hash("sha1WithRSAEncryption", formatMrz(sampleMRZ));
const concatenatedDataHashes = formatAndConcatenateDataHashes(
[[1, mrzHash], ...sampleDataHashes],
hashLen,
25
);

const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));

const privKey = forge.pki.privateKeyFromPem(mock_dsc_key_sha256_rsa_4096);
const modulus = privKey.n.toString(16);

const md = forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));

const signature = privKey.sign(md)
const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0));

return {
mrz: sampleMRZ,
signatureAlgorithm: signatureAlgorithm,
pubKey: {
modulus: hexToDecimal(modulus),
exponent: '65537',
},
dataGroupHashes: concatenatedDataHashes,
eContent: eContent,
encryptedDigest: signatureBytes,
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
}
}

function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash("sha1WithRSAEncryption", formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
console.log('dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');

const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - hashLen)
),
'concatHash is not at the right place in eContent'
);

const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10);
const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent);

const md = forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));

const signature = Buffer.from(encryptedDigest).toString(
'binary',
);

return rsaPublicKey.verify(md.digest().bytes(), signature);
}

const mockPassportData = genMockPassportData_sha256WithRSAEncryption_sha1MRZ_65537();
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
console.log("Signature valid:", verify(mockPassportData));

writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
47 changes: 47 additions & 0 deletions common/src/constants/mockPassportData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,52 @@ export const mockPassportData_sha256_rsa_65537 = {
photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3...',
};

export const mockPassportData_sha256_sha1MRZ_rsa_65537 = {
"mrz": "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
"signatureAlgorithm": "sha256WithRSAEncryption",
"pubKey": {
"modulus": "27722120859333796503211640489272106120482551309704222232072105246845695714472954540683236867192299062797225680861251026190519870822156282999820409388675151765188628354552148938026850533650560867351408820412089579679221235019315835956735754682911229932082922199789065846580784551244478494045799922879186142888909932141440466887670680548782372812836055118025224108859421921417110274504449719569511693219364768629052062228602555209299817554923972956312358490198380965414649591746119573796271477447999603941176493312445059119331560661900807731353542415313085750811411021804391084707844781744245549952173517229880392612399",
"exponent": "65537"
},
"dataGroupHashes": [
28, 76, -100, 59, 66, 120, 89, -69, -43, -105, -52, 112, -51, -97, -87, 43, 70, 38, 124, -14,
-101, -82, 11, -86, 55, -96, 114, -93, 25, 75, 70, 94, 85, 95, 40, -11, -101, 88, -85, -108,
-10, -44, 104, -62, -117, -66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6,
-14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38, 0, -62, 104, 108,
-19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110,
102, -6, -43, -82, -125, -85, -82, -120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81,
20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124, 41, -22,
106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47,
-67, -55, -123, 6, 121, 34, -125, 64, -114, 91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118,
-3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
38, 76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59,
-100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38
],
"eContent": [
49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1,
48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49,
55, 50, 50, 51, 56, 90, 48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4, 49, 34, 4, 32, -106,
-48, 111, 42, -56, -31, -10, 49, -55, -94, 3, 22, 26, 32, -12, 12, -68, 7, 60, -106, 94, -61,
-94, 123, 70, 48, 76, -92, -58, 16, 67, -43
],
"encryptedDigest": [
167, 166, 158, 72, 114, 46, 63, 61, 225, 67, 113, 130, 245, 238, 181, 23, 112, 117, 69, 171, 30,
222, 180, 22, 245, 137, 239, 157, 46, 7, 234, 178, 45, 4, 67, 234, 225, 148, 126, 214, 99, 107,
34, 109, 199, 229, 32, 233, 11, 151, 172, 106, 60, 99, 155, 63, 191, 74, 205, 156, 217, 108,
228, 75, 64, 250, 209, 209, 37, 78, 22, 235, 81, 31, 146, 255, 138, 40, 68, 147, 160, 190, 4,
88, 211, 224, 183, 236, 67, 85, 25, 138, 232, 112, 241, 39, 2, 2, 240, 15, 25, 248, 78, 193, 54,
255, 154, 16, 128, 77, 217, 52, 52, 227, 179, 121, 133, 131, 3, 232, 114, 88, 19, 133, 163, 150,
139, 180, 68, 69, 129, 185, 53, 138, 177, 169, 245, 224, 74, 216, 57, 79, 214, 248, 208, 86, 89,
145, 25, 25, 42, 210, 159, 249, 171, 183, 13, 230, 214, 57, 182, 111, 228, 3, 170, 41, 170, 99,
62, 64, 67, 44, 81, 200, 111, 13, 115, 160, 140, 241, 97, 198, 62, 101, 106, 230, 65, 46, 184,
101, 230, 74, 44, 6, 126, 75, 180, 110, 68, 218, 17, 199, 177, 123, 131, 14, 186, 20, 83, 222,
2, 179, 114, 70, 252, 119, 112, 216, 196, 111, 51, 43, 103, 113, 196, 42, 197, 233, 71, 103,
138, 45, 238, 10, 215, 123, 32, 164, 178, 47, 233, 102, 94, 213, 74, 170, 56, 240, 40, 97, 40,
218, 191, 70, 12, 44
],
"photoBase64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
}

export const mockPassportData_sha1_rsa_65537 = {
mrz: 'P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02',
signatureAlgorithm: 'sha1WithRSAEncryption',
Expand Down Expand Up @@ -298,6 +344,7 @@ export const mockPassportData_sha512_ecdsa = {

export const mockPassportDatas = [
mockPassportData_sha256_rsa_65537,
mockPassportData_sha256_sha1MRZ_rsa_65537,
mockPassportData_sha1_rsa_65537,
mockPassportData_sha256_rsapss_65537,
mockPassportData_sha1_ecdsa,
Expand Down
10 changes: 10 additions & 0 deletions common/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ export function formatAndConcatenateDataHashes(
// // NULL tag + SEQUENCE + long form indicator + length (275 bytes)
// 5, 0, 48, -126, 1, 19,

// spain
// 48, -127, -79,
// 2, 1,
// 0,
// 48, 7, 6, 5,
// 1.3.14.3.2.26 is sha1
// 43, 14, 3, 2, 26,
// SEQUENCE + ...
// 48, -127, -94,

// => current conclusion is we should be able to just hardcode indexes
// => as they shouldn't change must for same sig alg.
// => wrong: our rsassaPss has less datagroups so the length is different (30 rather then 31)
Expand Down

0 comments on commit f513a43

Please sign in to comment.