mirror of
https://github.com/selfxyz/self.git
synced 2026-02-08 13:25:59 -05:00
139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import * as crypto from 'crypto';
|
|
import {
|
|
arraysAreEqual,
|
|
dataHashesObjToArray,
|
|
formatMrz,
|
|
assembleMrz,
|
|
findTimeOfSignature,
|
|
parsePubKeyString,
|
|
} from '../utils/utils';
|
|
import * as forge from 'node-forge';
|
|
import passportData from '../server/passportData.json';
|
|
|
|
// 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);
|
|
|
|
console.log('mrz: ', mrz);
|
|
|
|
// Transforms the dataHashes object into an array of arrays
|
|
const dataHashesAsArray = dataHashesObjToArray(passportData.dataGroupHashes);
|
|
|
|
const formmattedMrz = formatMrz(mrz);
|
|
|
|
const hash = crypto.createHash('sha256');
|
|
hash.update(Buffer.from(formmattedMrz));
|
|
const mrzHash = Array.from(hash.digest()).map(x => (x < 128 ? x : x - 256));
|
|
|
|
console.log('mrzHash:', mrzHash);
|
|
console.log('dataHashesAsArray[0][1]:', dataHashesAsArray[0][1]);
|
|
console.log(
|
|
'Are they equal ?',
|
|
arraysAreEqual(mrzHash, dataHashesAsArray[0][1]),
|
|
);
|
|
|
|
// Let's replace the first array with the MRZ hash
|
|
dataHashesAsArray.shift();
|
|
dataHashesAsArray.unshift([1, mrzHash]);
|
|
// Concaténons les dataHashes :
|
|
const concatenatedDataHashes: number[] = [].concat(
|
|
...dataHashesAsArray.map((dataHash: any) => {
|
|
dataHash[1].unshift(...[48, 37, 2, 1, dataHash[0], 4, 32]);
|
|
return dataHash[1];
|
|
}),
|
|
);
|
|
|
|
// Starting sequence. Should be the same for everybody, but not sure
|
|
concatenatedDataHashes.unshift(
|
|
...[
|
|
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1,
|
|
48, -126, 1, 17,
|
|
],
|
|
);
|
|
|
|
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,
|
|
),
|
|
);
|
|
|
|
// please hash concatenatedDataHashes
|
|
const concatenatedDataHashesHash = crypto.createHash('sha256');
|
|
concatenatedDataHashesHash.update(Buffer.from(concatenatedDataHashes));
|
|
const concatenatedDataHashesHashDigest = Array.from(
|
|
concatenatedDataHashesHash.digest(),
|
|
).map(x => (x < 128 ? x : x - 256));
|
|
|
|
// Now let's reconstruct the eContent
|
|
|
|
const constructedEContent = [];
|
|
|
|
// Detailed description is in private file r&d.ts for now
|
|
// First, the tag and length, assumed to be always the same
|
|
constructedEContent.push(...[49, 102]);
|
|
|
|
// 1.2.840.113549.1.9.3 is RFC_3369_CONTENT_TYPE_OID
|
|
constructedEContent.push(
|
|
...[48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3],
|
|
);
|
|
// 2.23.136.1.1.1 is ldsSecurityObject
|
|
constructedEContent.push(...[49, 8, 6, 6, 103, -127, 8, 1, 1, 1]);
|
|
|
|
// 1.2.840.113549.1.9.5 is signing-time
|
|
constructedEContent.push(
|
|
...[48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5],
|
|
);
|
|
// time of the signature
|
|
constructedEContent.push(
|
|
...findTimeOfSignature(passportData.eContentDecomposed),
|
|
);
|
|
// 1.2.840.113549.1.9.4 is RFC_3369_MESSAGE_DIGEST_OID
|
|
constructedEContent.push(
|
|
...[48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4],
|
|
);
|
|
// TAG and length of the message digest
|
|
constructedEContent.push(...[49, 34, 4, 32]);
|
|
|
|
constructedEContent.push(...concatenatedDataHashesHashDigest);
|
|
|
|
console.log('constructedEContent', constructedEContent);
|
|
console.log('passportData.eContent', passportData.eContent);
|
|
console.log(
|
|
'Are they equal ?',
|
|
arraysAreEqual(constructedEContent, passportData.eContent),
|
|
);
|
|
|
|
// now let's verify the signature
|
|
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),
|
|
);
|
|
|
|
// SHA-256 hash of the eContent
|
|
const md = forge.md.sha256.create();
|
|
md.update(forge.util.binary.raw.encode(new Uint8Array(constructedEContent)));
|
|
const hashOfEContent = md.digest().getBytes();
|
|
|
|
// Signature verification
|
|
const signatureBytes = Buffer.from(passportData.encryptedDigest).toString(
|
|
'binary',
|
|
);
|
|
const valid = publicKey.verify(hashOfEContent, signatureBytes);
|
|
|
|
if (valid) {
|
|
console.log('The signature is valid.');
|
|
} else {
|
|
console.log('The signature is not valid.');
|
|
}
|